類加載器

      網友投稿 804 2025-03-31

      類加載過程


      加載->連接->初始化。連接過程又可分為三步:驗證->準備->解析。

      類加載器分類

      JVM 中內置了三個重要的 ClassLoader,除了 BootstrapClassLoader 其他類加載器均由 Java 實現且全部繼承自java.lang.ClassLoader:

      啟動類加載器(Bootstrap ClassLoader)此類加載器負責將存放在 \lib 目錄中的,或者被 -Xbootclasspath 參數所指定的路徑中的,并且是虛擬機識別的(僅按照文件名識別,如 rt.jar,名字不符合的類庫即使放在 lib 目錄中也不會被加載)類庫加載到虛擬機內存中。啟動類加載器無法被 Java 程序直接引用,用戶在編寫自定義類加載器時,如果需要把加載請求委派給啟動類加載器,直接使用 null 代替即可。

      擴展類加載器(Extension ClassLoader)這個類加載器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實現的。它負責將 /lib/ext 或者被 java.ext.dir 系統變量所指定路徑中的所有類庫加載到內存中,開發者可以直接使用擴展類加載器。

      應用程序類加載器(Application ClassLoader)這個類加載器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)實現的。由于這個類加載器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此一般稱為系統類加載器。它負責加載用戶類路徑(ClassPath)上所指定的類庫,開發者可以直接使用這個類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

      雙親委派模型

      每一個類都有一個對應它的類加載器。系統中的 ClassLoder 在協同工作的時候會默認使用?雙親委派模型?。

      1、在類加載的時候,系統會首先判斷當前類是否被加載過。已經被加載的類會直接返回,否則才會嘗試加載。

      2、加載的時候,首先會把該請求委派該父類加載器的?loadClass()?處理,因此所有的請求最終都應該傳送到頂層的啟動類加載器?BootstrapClassLoader?中。當父類加載器無法處理時,才由自己來處理。

      3、當父類加載器為null時,會使用啟動類加載器?BootstrapClassLoader?作為父類加載器。

      好處

      使得 Java 類隨著它的類加載器一起具有一種帶有優先級的層次關系,從而使得基礎類得到統一。

      例如 java.lang.Object 存放在 rt.jar 中,如果編寫另外一個 java.lang.Object 并放到 ClassPath 中,程序可以編譯通過。

      由于雙親委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 優先級更高,這是因為 rt.jar 中的 Object 使用的是啟動類加載器,而 ClassPath 中的 Object 使用的是應用程序類加載器。

      rt.jar 中的 Object 優先級更高,那么程序中所有的 Object 都是這個 Object。

      保證了Java程序的穩定運行,可以避免類的重復加載(JVM 區分不同類的方式不僅僅根據類名,相同的類文件被不同的類加載器加載產生的是兩個不同的類),也保證了 Java 的核心 API 不被篡改。

      如果沒有使用雙親委派模型,而是每個類加載器加載自己的話就會出現一些問題,比如我們編寫一個稱為?java.lang.Object?類的話,那么程序運行的時候,系統就會出現多個不同的?Object?類。

      注意

      這個雙親翻譯的容易讓人誤解,一般理解雙親都是父母,這里的雙親表達的是“父母一輩”的人,并不是說真的有一個 Mother ClassLoader 和一個 Father ClassLoader 。另外,類加載器之間的“父子”關系也不是通過繼承來體現的,是由“優先級”來決定。官方API文檔對這部分的描述如下:

      The Java platform uses a delegation model for loading classes.?The basic idea is that every class loader has a "parent" class loader.?When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.

      源碼分析

      private final ClassLoader parent;

      protected Class loadClass(String name, boolean resolve)

      throws ClassNotFoundException

      {

      synchronized (getClassLoadingLock(name)) {

      // 首先檢查請求的類是否已經被加載過

      Class c = findLoadedClass(name);

      if (c == null) {

      long t0 = System.nanoTime();

      try {

      if (parent != null) {

      //父加載器不為空,調用父加載器loadClass()方法處理

      c = parent.loadClass(name, false);

      } else {

      //父加載器為空,使用啟動類加載器 BootstrapClassLoader 加載

      c = findBootstrapClassOrNull(name);

      }

      } catch (ClassNotFoundException e) {

      //父類加載器無法完成加載請求

      }

      if (c == null) {

      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;

      }

      }

      自定義加載器

      除了?BootstrapClassLoader?其他類加載器均由 Java 實現且全部繼承自java.lang.ClassLoader。如果我們要自定義自己的類加載器,很明顯需要繼承?ClassLoader。

      示例:自定義一個NetworkClassLoader,用于加載網絡上的class文件

      package classloader;

      import java.io.ByteArrayOutputStream;

      import java.io.InputStream;

      import java.net.URL;

      /**

      * 加載網絡class的ClassLoader

      */

      public class NetworkClassLoader extends ClassLoader {

      private String rootUrl;

      public NetworkClassLoader(String rootUrl) {

      this.rootUrl = rootUrl;

      }

      @Override

      protected Class findClass(String name) throws ClassNotFoundException {

      Class clazz = null;//this.findLoadedClass(name); // 父類已加載

      //if (clazz == null) { //檢查該類是否已被加載過

      byte[] classData = getClassData(name); //根據類的二進制名稱,獲得該class文件的字節碼數組

      if (classData == null) {

      類加載器

      throw new ClassNotFoundException();

      }

      clazz = defineClass(name, classData, 0, classData.length); //將class的字節碼數組轉換成Class類的實例

      //}

      return clazz;

      }

      private byte[] getClassData(String name) {

      InputStream is = null;

      try {

      String path = classNameToPath(name);

      URL url = new URL(path);

      byte[] buff = new byte[1024*4];

      int len = -1;

      is = url.openStream();

      ByteArrayOutputStream baos = new ByteArrayOutputStream();

      while((len = is.read(buff)) != -1) {

      baos.write(buff,0,len);

      }

      return baos.toByteArray();

      } catch (Exception e) {

      e.printStackTrace();

      } finally {

      if (is != null) {

      try {

      is.close();

      } catch(IOException e) {

      e.printStackTrace();

      }

      }

      }

      return null;

      }

      private String classNameToPath(String name) {

      return rootUrl + "/" + name.replace(".", "/") + ".class";

      }

      }

      JAR Java

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:如何用excel做甘特圖教程
      下一篇:Excel 表格技巧—數據透視表標簽項重復顯示與合并行標簽
      相關文章
      亚洲精品无码久久久久YW| 亚洲成人在线免费观看| 水蜜桃亚洲一二三四在线| 亚洲国产高清视频在线观看| 亚洲伊人久久大香线蕉综合图片| 亚洲国产精品碰碰| 久久水蜜桃亚洲AV无码精品| 亚洲Av无码国产一区二区| wwwxxx亚洲| 国产乱辈通伦影片在线播放亚洲| 精品久久亚洲一级α| va亚洲va日韩不卡在线观看| 国产成人va亚洲电影| 亚洲精品无码日韩国产不卡?V| 亚洲成?v人片天堂网无码| 亚洲人成网站色在线入口| 综合亚洲伊人午夜网| 亚洲精品无码久久千人斩| 久久精品国产亚洲AV麻豆王友容| 亚洲av一综合av一区| 911精品国产亚洲日本美国韩国 | 亚洲AV永久青草无码精品| 亚洲AV无码成人精品区天堂| 亚洲男人第一av网站| 亚洲国产视频一区| 久久亚洲国产成人影院| 亚洲爆乳大丰满无码专区| 国产99久久亚洲综合精品| 亚洲七七久久精品中文国产| 国产综合亚洲专区在线| 国产亚洲精品xxx| 99久久亚洲综合精品成人网| 亚洲国产模特在线播放| 亚洲xxxx视频| 大胆亚洲人体视频| 亚洲中文字幕无码久久综合网| 亚洲av片劲爆在线观看| 亚洲成aⅴ人片在线影院八| 亚洲日韩精品国产3区| | 亚洲精品美女在线观看|