<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java雜談之類加載雙親委派機制

          共 9600字,需瀏覽 20分鐘

           ·

          2021-06-13 02:27


          1、類加載器--加載類的開放性

          類加載器(ClassLoader)是Java語言的一項創(chuàng)新,也是Java流行的一個重要原因。在類加載的第一階段“加載”過程中,需要通過一個類的全限定名來獲取定義此類的二進制字節(jié)流,完成這個動作的代碼塊就是類加載器。這一動作是放在Java虛擬機外部去實現(xiàn)的,以便讓應(yīng)用程序自己決定如何獲取所需的類。

          虛擬機規(guī)范并沒有指明二進制字節(jié)流要從一個Class文件獲取,或者說根本沒有指明從哪里獲取、怎樣獲取。這種開放使得Java在很多領(lǐng)域得到充分運用,例如:

          從ZIP包中讀取,這很常見,成為JAR,EAR,WAR格式的基礎(chǔ)
          從網(wǎng)絡(luò)中獲取,最典型的應(yīng)用就是Applet運行時計算生成,最典型的是動態(tài)代理技術(shù),在java.lang.reflect.Proxy中,就是用了ProxyGenerator.generateProxyClass來為特定接口生成形式為“*

          2、類加載器--類的唯一性

          類加載器雖然只用于實現(xiàn)類的加載動作,但是對于任意一個類,都需要由加載它的類加載器和這個類本身共同確立其在Java虛擬機中的唯一性。通俗的說,JVM中兩個類是否“相等”,首先就必須是同一個類加載器加載的,否則,即使這兩個類來源于同一個Class文件,被同一個虛擬機加載,只要類加載器不同,那么這兩個類必定是不相等的。

          這里的“相等”,包括代表類的Class對象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回結(jié)果,也包括使用instanceof關(guān)鍵字做對象所屬關(guān)系判定等情況。

          以下代碼說明了不同的類加載器對instanceof關(guān)鍵字運算的結(jié)果的影響。

          @Test
          public void test_load_class() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
              ClassLoader classLoader = new ClassLoader() {

                  @Override
                  public Class<?> loadClass(String name) throws ClassNotFoundException {
                      try {
                          String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                          InputStream inputStream = getClass().getResourceAsStream(fileName);
                          if(inputStream==null){
                              return super.loadClass(name);
                          }
                          byte[] bytes = new byte[inputStream.available()];
                          inputStream.read(bytes);
                          return defineClass(name, bytes, 0, bytes.length);
                      } catch (Exception e) {
                          throw new ClassNotFoundException();
                      }
                  }
              };

              Class<?> aClass = this.getClass().getClassLoader().loadClass("com.niu.controller.TestJar");
              Object object = aClass.newInstance();
              System.out.println(object instanceof com.niu.controller.TestJar);

              Class<?> bClass = classLoader.loadClass("com.niu.controller.TestJar");
              Object object2 = bClass.newInstance();
              System.out.println(object2 instanceof com.niu.controller.TestJar);
          }

          輸出結(jié)果:

          class com.jvm.classloading.ClassLoaderTest
          true
          class com.jvm.classloading.ClassLoaderTest
          false

          myLoader是自定義的類加載器,可以用來加載與自己在同一路徑下的Class文件。main函數(shù)的第一部分使用系統(tǒng)加載主類ClassLoaderTest的類加載器加載ClassLoaderTest,輸出顯示,obj1的所屬類型檢查正確,這是虛擬機中有2個ClassLoaderTest類,一個是主類,另一個是main()方法中加載的類,由于這兩個類使用同一個類加載器加載并且來源于同一個Class文件,因此這兩個類是完全相同的。

          第二部分使用自定義的類加載器加載ClassLoaderTest,class com.jvm.classloading.ClassLoderTest顯示,obj2確實是類com.jvm.classloading.ClassLoaderTest實例化出來的對象,但是第二句輸出false。此時虛擬機中有3個ClassLoaderTest類,由于第3個類的類加載器與前面2個類加載器不同,雖然來源于同一個Class文件,但它是一個獨立的類,所屬類型檢查是返回結(jié)果自然是false。

          3、雙親委派模型--類加載器種類

          從Java虛擬機的角度來說,只存在兩種不同的類加載器:一種是啟動類加載器(Bootstrap ClassLoader),這個類加載器使用C++語言實現(xiàn)(HotSpot虛擬機中),是虛擬機自身的一部分;另一種就是所有其他的類加載器,這些類加載器都有Java語言實現(xiàn),獨立于虛擬機外部,并且全部繼承自java.lang.ClassLoader。

          從開發(fā)者的角度,類加載器可以細分為:

          • 啟動(Bootstrap)類加載器:負責(zé)將 Java_Home/lib下面的類庫加載到內(nèi)存中(比如rt.jar)。由于引導(dǎo)類加載器涉及到虛擬機本地實現(xiàn)細節(jié),開發(fā)者無法直接獲取到啟動類加載器的引用,所以不允許直接通過引用進行操作。

          • 標(biāo)準(zhǔn)擴展(Extension)類加載器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實現(xiàn)的。它負責(zé)將Java_Home /lib/ext或者由系統(tǒng)變量 java.ext.dir指定位置中的類庫加載到內(nèi)存中。開發(fā)者可以直接使用標(biāo)準(zhǔn)擴展類加載器。

          • 應(yīng)用程序(Application)類加載器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)實現(xiàn)的。它負責(zé)將系統(tǒng)類路徑(CLASSPATH)中指定的類庫加載到內(nèi)存中。開發(fā)者可以直接使用系統(tǒng)類加載器。由于這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,因此一般稱為系統(tǒng)(System)加載器。

          • 除此之外,還有自定義的類加載器,它們之間的層次關(guān)系被稱為類加載器的雙親委派模型。該模型要求除了頂層的啟動類加載器外,其余的類加載器都應(yīng)該有自己的父類加載器,而這種父子關(guān)系一般通過組合(Composition)關(guān)系來實現(xiàn),而不是通過繼承(Inheritance)。



          • 4、雙親委派模型

            某個特定的類加載器在接到加載類的請求時,首先將加載任務(wù)委托給父類加載器,依次遞歸,如果父類加載器可以完成類加載任務(wù),就成功返回;只有父類加載器無法完成此加載任務(wù)時,才自己去加載。

            使用雙親委派模型的好處在于Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系。例如類java.lang.Object,它存在在rt.jar中,無論哪一個類加載器要加載這個類,最終都是委派給處于模型最頂端的Bootstrap ClassLoader進行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個類。相反,如果沒有雙親委派模型而是由各個類加載器自行加載的話,如果用戶編寫了一個java.lang.Object的同名類并放在ClassPath中,那系統(tǒng)中將會出現(xiàn)多個不同的Object類,程序?qū)⒒靵y。因此,如果開發(fā)者嘗試編寫一個與rt.jar類庫中重名的Java類,可以正常編譯,但是永遠無法被加載運行。

            在java.lang.ClassLoader的loadClass()方法中,先檢查是否已經(jīng)被加載過,若沒有加載則調(diào)用父類加載器的loadClass()方法,若父加載器為空則默認使用啟動類加載器作為父加載器。如果父加載失敗,則拋出ClassNotFoundException異常后,再調(diào)用自己的findClass()方法進行加載。

            protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{
                synchronized (getClassLoadingLock(name)) {
                    // First, check if the class has already been loaded
                    Class<?> c = findLoadedClass(name);
                    if (c == null) {
                        long t0 = System.nanoTime();
                        try {
                            if (parent != null) {
                                c = parent.loadClass(name, false);
                            } else {
                                c = findBootstrapClassOrNull(name);
                            }
                        } catch (ClassNotFoundException e) {
                            // ClassNotFoundException thrown if class not found
                            // from the non-null parent class loader
                        }

                        if (c == null) {
                            // If still not found, then invoke findClass in order
                            // to find the class.
                            long t1 = System.nanoTime();
                            c = findClass(name);

                            // this is the defining class loaderrecord the stats
                            sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                            sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                            sun.misc.PerfCounter.getFindClasses().increment();
                        }
                    }
                    if (resolve) {
                        resolveClass(c);
                    }
                    return c;
                }
            }

            注意,雙親委派模型是Java設(shè)計者推薦給開發(fā)者的類加載器的實現(xiàn)方式,并不是強制規(guī)定的。大多數(shù)的類加載器都遵循這個模型,但是JDK中也有較大規(guī)模破壞雙親模型的情況,例如線程上下文類加載器(Thread Context ClassLoader)的出現(xiàn),具體分析可以參見周志明著《深入理解Java虛擬機》。

          — 【 THE END 】—
          本公眾號全部博文已整理成一個目錄,請在公眾號里回復(fù)「m」獲取!

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點“在看”,關(guān)注公眾號并回復(fù) PDF 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人妻在线视频播放 | 国产精品成人无码a无码 | 婷婷在线成人视频精品 | 国产色色色色 | www.18av |