<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      JVM學習記錄-類加載器

      前言

      JVM設計團隊把類加載階段中的“通過一個類的全限定名來獲取描述此類的二進制字節流”這個動作放到Java虛擬機外面去實現,以便讓應用程序自己決定如何去獲取所需要的類。實現這個動作的代碼模塊稱為“類加載器”。

      類與類加載器

      類加載器雖然只用戶實現類的加載動作,但它在Java程序中起到的作用卻遠遠不限于類加載階段。每個類都有一個獨立的類名稱空間,在比較兩個類是否“相等”,只有兩個類是由同一個類加載器加載的前提下才有意義,否則即使兩個類來源于同一個Class文件,被同一個虛擬機加載,只要加載它們的類加載器不同,那這兩個類就必定不相等。

      這里的相等,包含Class對象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回結果,也包括使用instanceof關鍵字做對象所屬關系判定等情況。例如如下代碼:

      public class ClassLoaderTest {
      
          public static void main(String[] args) throws Exception{
      
              ClassLoader myClassLoader = new ClassLoader() {
                  /**
                   * Loads the class with the specified <a href="#name">binary name</a>.
                   * This method searches for classes in the same manner as the {@link
                   * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
                   * machine to resolve class references.  Invoking this method is equivalent
                   * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
                   * false)</tt>}.
                   *
                   * @param name The <a href="#name">binary name</a> of the class
                   * @return The resulting <tt>Class</tt> object
                   * @throws ClassNotFoundException If the class was not found
                   */
                  @Override
                  public Class<?> loadClass(String name) throws ClassNotFoundException {
                      try{
                          String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
      
                          InputStream inputStream = getClass().getResourceAsStream(fileName);
                          if(null == inputStream){
                              return super.loadClass(name);
                          }
                          byte[] b = new byte[inputStream.available()];
                          inputStream.read(b);
                          return defineClass(name,b,0,b.length);
                      }catch (IOException e){
                          throw new ClassNotFoundException(name);
                      }
      
                  }
              };
      
              Object obj = myClassLoader.loadClass("com.eurekaclient2.client2.shejimoshi.JVM.ClassLoaderTest").newInstance();
      
              System.out.println("來源:"+obj.getClass());
      
              System.out.println(obj instanceof com.eurekaclient2.client2.shejimoshi.JVM.ClassLoaderTest);
          }
      
      }

      運行結果:

      來源:class com.eurekaclient2.client2.shejimoshi.JVM.ClassLoaderTest
      false

      從運行結果中我們可以看出來,obj對象確實屬于ClassLoaderTest類的對象,但是從運行結果的第二行中可以看出來,這個對象與ClassLoaderTest類做所屬類型檢查時返回的false,因為虛擬機中存在了兩個ClassLoaderTest類,一個是由系統應用程序類加載器加載的,另一個是由我們自定義的類加載器加載的,雖然都來自同一個Class文件,但依然是兩個獨立的類。

      雙親委派模型

      從虛擬機的角度來講,只存在兩種不同的類加載器:一種是啟動類加載器(Bootstrap ClassLoader);另一種就是所有其他的類加載器,這些類加載器都是由Java語言實現,并且獨立于虛擬機外部,并都繼承自抽象類java.lang.ClassLoader。

      從Java開人員的角度來看,類加載器可以分的更細一些,但是絕大部分java程序都會用到下面的這3種系統提供的類加載器。

      啟動類加載器(Bootstrap ClassLoader):它負責將放在<JAVA_HOME>\lib目錄中的,或者被-Xbootclasspath參數所指定的路徑中,并且是虛擬機識別的類庫加載到虛擬機中。

      擴展類加載器(Extension ClassLoader):它負責加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統變量所指定的路徑中的所有類庫,開發者可以直接使用擴展類加載器。

      應用程序類加載器(Application ClassLoader):它一般被稱為系統類加載器,負責加載用戶類路徑上所指定的類庫,開發者可以直接使用這個類加載器,若應用程序中沒有自定義過類加載器,一般情況下默認的就是這個應用程序類加載器。

      我們的應用程序都是由這3種類加載器相互配合進行加載的,如果有需要,還可以加入自定義的類加載器。這些類加載器的關系如下圖:

       

      類加載器的之間的這種層次關系,稱為類加載器的雙親委派模式(Parents Delegation Model)。這種模型要求,除了頂層外,其余的類加載器都應當有自己的的父類加載器。這里的子父關系一般不會以繼承方式來實現,而是使用組合關系來復用父加載器的代碼。

      雙親委派模型的工作過程:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是這樣,最終都應該傳送到頂層的啟動類加載器中,只有當父類反饋自己無法完成這個加載請求時,子加載器才會嘗試自己去加載。

       使用雙親委派模型來組織類加載器之間的關系,有一個顯而易見測好處就是Java類隨著它的類加載器一起具備了一種帶有優先級的層次關系。

      記得以前看到過一個面試題,題目大概意思是:能不能自己寫一個類叫java.lang.String?

      答案:不可以。原因就是因為JVM的類加載器采用的這種雙親委派模型,當我們寫了一個類叫java.lang.String時,類加載器發現已經加載過一個同樣的類了,不用加載了,直接使用就可以了。所以自己寫的這個java.lang.String這個類可以編譯通過,但是無法被加載運行。

      實現雙親委派的代碼集中在java.lang.ClassCloader的loadClass()方法中,邏輯很簡單:首先檢查自己是否已經被加載過,如果沒有加載則調用父加載器的loadClass()方法,若父加載器為空則默認使用啟動類加載器作為父加載器。如果父加載器加載失敗,則拋出ClassNotFoundException異常后,再調用自己的findClass()方法進行加載。

      loadClass的源碼:

      /**
           * Loads the class with the specified <a href="#name">binary name</a>.  The
           * default implementation of this method searches for classes in the
           * following order:
           *
           * <ol>
           *
           *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
           *   has already been loaded.  </p></li>
           *
           *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
           *   on the parent class loader.  If the parent is <tt>null</tt> the class
           *   loader built-in to the virtual machine is used, instead.  </p></li>
           *
           *   <li><p> Invoke the {@link #findClass(String)} method to find the
           *   class.  </p></li>
           *
           * </ol>
           *
           * <p> If the class was found using the above steps, and the
           * <tt>resolve</tt> flag is true, this method will then invoke the {@link
           * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
           *
           * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
           * #findClass(String)}, rather than this method.  </p>
           *
           * <p> Unless overridden, this method synchronizes on the result of
           * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
           * during the entire class loading process.
           *
           * @param  name
           *         The <a href="#name">binary name</a> of the class
           *
           * @param  resolve
           *         If <tt>true</tt> then resolve the class
           *
           * @return  The resulting <tt>Class</tt> object
           *
           * @throws  ClassNotFoundException
           *          If the class could not be found
           */
          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 loader; record 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強制性要求的一個模型,而是Java設計者推薦給開發者的類加載器的實現方式。在Java世界中大部分的類加載器都遵循這個模型,但也有例外,雙親委派模型到目前為止主要出現過3次較大規模的“被破壞”情況。

      • 第一次:由于類加載器是JDK1.0就已經存在了,而雙親委派模型在JDK1.2之后才被引入,所以為了向前兼容,做了一些妥協。在JDK1.2以后已不再提倡用戶去覆蓋loadClass()方法,而應該把自己的實現邏輯寫在findClass()方法中,這樣在loadClass方法中如果父類加載器加載失敗,就會調用自己的findClass方法來完成加載,這樣就保證了自己實現的類加載器符合雙親委派模型了。
      • 第二次:雙親委派模型的規則是自低向上(由子到父)來進行加載的,但是有些情況下父類是需要調用子類的代碼,這種情況就需要破壞這個模型了。為了解決這種情況,Java設計團隊,引入了一個新的加載器:線程上下文加載器(Trhead Context ClassLoader)。這個類加載器可以通過java.lang.Thread類的setCOntextClassLoader()方法進行設置,通過getContextClassLoader()方法來獲得。如果創建線程時還未設置,它會從父線程中繼承一個,如果在應用程序的全局范圍內都沒有設置過的話,那這個類加載器就是應用程序類加載器了。Java中所有涉及SPI的加載動作基本上都采用這種方式,例如:JNDI、JDBC、JCE、JAXB、和JBI等。其實我們常用的Tomcat這種應用服務器也是使用的這種類加載器。
      • 第三次:為了實現熱部署,熱插拔,模塊化等功能。就是說更新了一些模塊而不需要重啟,只需要把類和類加載器一同替換掉就可以實現熱部署了。

       

       

       

       

      posted @ 2018-05-28 23:38  紀莫  閱讀(736)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品美女一区二区三| 国产av一区二区麻豆熟女| 亚洲二区中文字幕在线| 国产精品不卡一区二区在线| 久久国产精品不只是精品| 少妇太爽了在线观看免费视频 | 国产精品一区二区日韩精品| 最新精品国偷自产在线| 无码抽搐高潮喷水流白浆| 国产爆乳无码av在线播放| 南木林县| 亚洲Av综合日韩精品久久久| 亚洲熟妇在线视频观看| 亚洲国产成人无码av在线播放 | 亚洲熟女乱色一区二区三区| 亚洲av片在线免费观看| 97久久精品无码一区二区天美| 高清有码国产一区二区| 香蕉久久精品日日躁夜夜躁夏| 绝顶丰满少妇av无码| 色老头在线一区二区三区| 亚欧洲乱码视频一二三区| 久久97人人超人人超碰超国产| 双鸭山市| 一本色道婷婷久久欧美| 国产精品熟女亚洲av麻豆| 九九热免费在线视频观看| 9久9久热精品视频在线观看 | 无码里番纯肉h在线网站| 国产福利酱国产一区二区| 久久一亚色院精品全部免费| 狠狠综合久久av一区二| 人妻少妇精品视频专区| 精品日韩人妻中文字幕| 三河市| 日韩丝袜人妻中文字幕| 在线观看特色大片免费网站 | 国产精品久久久福利| 97久久综合亚洲色hezyo| 嘉定区| 欧美日产国产精品日产|