JVM中的類加載

      網(wǎng)友投稿 587 2025-03-31

      類加載器


      把類加載階段中的"通過一個類的全限定名來獲取描述此類的二進(jìn)制字節(jié)流"這個動作放到Java虛擬機(jī)外部去實(shí)現(xiàn),以便讓應(yīng)用程序自己決定如何去獲取所需要的類,實(shí)現(xiàn)這個動作的代碼模塊稱為類加載器。

      自定義類加載器

      現(xiàn)在有個需求在項(xiàng)目中我們需要加載一個特定目錄下的class文件【c:\tools\myClassLoader】,這時我們需要自己來定義特定的類加載器。

      1.創(chuàng)建自定義類加載器

      繼承ClassLoader后重寫了findClass方法加載指定路徑上的class,代碼如下:

      import java.nio.file.Files; import java.nio.file.Paths; /** * 自定義類加載器 * @author 波波烤鴨 * @email dengpbs@163.com * */ public class MyClassLoader extends ClassLoader { // 加載的路徑 private String path; public MyClassLoader(String path) { super(); this.path = path; } @Override protected Class findClass(String name) throws ClassNotFoundException { try { byte[] result = getClass(name); if (result == null) { throw new ClassNotFoundException(); } else { // 將字節(jié)流轉(zhuǎn)換為Class對象 return defineClass(name, result, 0, result.length); } } catch (Exception e) { e.printStackTrace(); } return null; } // 加載class為字節(jié)數(shù)組 private byte[] getClass(String name) { try { return Files.readAllBytes(Paths.get(path)); } catch (Exception e) { e.printStackTrace(); } return null; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      JVM中的類加載器

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      2.測試

      指定目錄下存放編譯好的class文件,注意用相關(guān)的jdk版本編譯

      public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { MyClassLoader myLoader = new MyClassLoader("C:\\tools\\myClassLoader\\User.class"); Class clazz = myLoader.loadClass("com.dpb.pojo.User"); Object object = clazz.newInstance(); System.out.println(object); System.out.println(object.getClass().getClassLoader()); }

      1

      2

      3

      4

      5

      6

      7

      輸出結(jié)果

      com.dpb.pojo.User@4e25154f com.dpb.loader.MyClassLoader@6d06d69c

      1

      2

      實(shí)現(xiàn)了加載特定目錄下的class文件

      ClassLoader

      上面的代碼雖然實(shí)現(xiàn)加載特定目錄下的class文件,但這么執(zhí)行的原因是什么呢?要了解這個我們需要來具體看下ClassLoader的源代碼。代碼比較多,截取了核心的代碼

      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); // 獲取類加載器 如果為null 本方法就結(jié)束了 if (c == null) { long t0 = System.nanoTime(); try { // 如果parent為null if (parent != null) { // 獲取 父類加載器 c = parent.loadClass(name, false); } else { // 使用引導(dǎo)加載器 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } // 如果所有的父加載器都沒有找到Class if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); // 就調(diào)用自身的findClass方法去加載類 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; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      // 本方法并沒有去查找Class,本方法留給子類去重寫的 protected Class findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }

      1

      2

      3

      4

      所以如果我們需要加載特定的Class文件的時候只需要重寫findClass方法即可,而不用去重寫loadClass方法。

      雙親委派模型

      通過ClassLoader中的loadClass方法我們發(fā)現(xiàn)類加載器加類的時候有既定的原則,而且系統(tǒng)提供的類加載器好像也不止一個,我們就來說下這塊。系統(tǒng)給我們提供了三個類加載器,如下

      1.啟動類加載器

      public static void main(String[] args) { System.out.println("BootStrap:"+String.class.getClassLoader()); System.out.println(System.getProperty("sun.boot.class.path")); }

      1

      2

      3

      4

      啟動類加載器我們無法通過程序獲取,所以打印結(jié)果為null,可是加載資源的路徑可以獲取。

      BootStrap:null C:\Program Files\Java\jre1.8.0_144\lib\resources.jar; C:\Program Files\Java\jre1.8.0_144\lib\rt.jar; C:\Program Files\Java\jre1.8.0_144\lib\sunrsasign.jar; C:\Program Files\Java\jre1.8.0_144\lib\jsse.jar; C:\Program Files\Java\jre1.8.0_144\lib\jce.jar; C:\Program Files\Java\jre1.8.0_144\lib\charsets.jar; C:\Program Files\Java\jre1.8.0_144\lib\jfr.jar; C:\Program Files\Java\jre1.8.0_144\classes

      1

      2

      3

      4

      5

      6

      7

      8

      9

      2.擴(kuò)展類加載器

      public static void main(String[] args) { System.out.println(System.getProperty("java.ext.dirs")); }

      1

      2

      3

      加載路徑如下:

      C:\Program Files\Java\jre1.8.0_144\lib\ext; C:\Windows\Sun\Java\lib\ext

      1

      2

      我們也可以將自己的文件打成jar包放到擴(kuò)展目錄下,也會被擴(kuò)展類加載器加載。

      3.系統(tǒng)類加載器

      public static void main(String[] args) { System.out.println(System.getProperty("java.class.path")); }

      1

      2

      3

      加載路徑

      C:\Users\dengp\Desktop\共享文件\Java1112\workspace\others\FreemarkerDemo\target\classes; C:\Users\dengp\.m2\repository\org\springframework\spring-context\4.3.21.RELEASE\spring-context-4.3.21.RELEASE.jar; C:\Users\dengp\.m2\repository\org\springframework\spring-aop\4.3.21.RELEASE\spring-aop-4.3.21.RELEASE.jar; C:\Users\dengp\.m2\repository\org\springframework\spring-beans\4.3.21.RELEASE\spring-beans-4.3.21.RELEASE.jar; C:\Users\dengp\.m2\repository\org\springframework\spring-core\4.3.21.RELEASE\spring-core-4.3.21.RELEASE.jar; C:\Users\dengp\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar; C:\Users\dengp\.m2\repository\org\springframework\spring-expression\4.3.21.RELEASE\spring-expression-4.3.21.RELEASE.jar; C:\Users\dengp\.m2\repository\org\springframework\spring-webmvc\4.3.21.RELEASE\spring-webmvc-4.3.21.RELEASE.jar; C:\Users\dengp\.m2\repository\org\springframework\spring-web\4.3.21.RELEASE\spring-web-4.3.21.RELEASE.jar; C:\Users\dengp\.m2\repository\org\freemarker\freemarker\2.3.28\freemarker-2.3.28.jar; C:\Users\dengp\.m2\repository\org\springframework\spring-context-support\4.3.21.RELEASE\spring-context-support-4.3.21.RELEASE.jar

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      雙親委派描述:

      如果一個類加載器收到了類加載請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器完成,每一個層次的類加載器都是如果,因此所有的加載請求最終都應(yīng)該傳遞到頂層的啟動類加載器中

      當(dāng)父加載器反饋無法加載該類時(搜索范圍中沒有找到所需的類),子加載器才會嘗試自己去加載。

      弄清楚這個委派模型后再去看loadClass方法中的邏輯應(yīng)該就比較容易了。

      參考《深入理解Java虛擬機(jī)》

      Java JVM

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:如何根據(jù)Excel中另一個單元格的顏色或格式選擇單元格?
      下一篇:銷售/HR/運(yùn)營/產(chǎn)品全新模板上線
      相關(guān)文章
      国产精品亚洲四区在线观看| 亚洲AV无码专区国产乱码4SE| 国产aⅴ无码专区亚洲av| 最新亚洲人成网站在线观看| 国产精品亚洲精品青青青| 亚洲色图综合网站| 亚洲av成人无码久久精品 | 国产成人va亚洲电影| 亚洲av无码兔费综合| 亚洲欧美日韩中文字幕在线一区| 亚洲人成7777影视在线观看| 亚洲视频在线观看网站| 亚洲黄色在线观看视频| 亚洲美女aⅴ久久久91| 亚洲美女aⅴ久久久91| 亚洲人成日本在线观看| 亚洲一级大黄大色毛片| 亚洲一区中文字幕在线电影网| 亚洲三级在线视频| 国产亚洲精品影视在线| 亚洲综合精品成人| 亚洲大码熟女在线观看| 亚洲av色香蕉一区二区三区| 青青青亚洲精品国产| 亚洲国产精品综合久久网络| 亚洲国产精品狼友中文久久久| 亚洲国产成人久久综合碰| 久久久久亚洲精品中文字幕| 亚洲一区二区三区无码中文字幕 | 亚洲综合小说久久另类区| 亚洲日韩乱码中文无码蜜桃| 亚洲一级毛片免观看| 亚洲午夜理论片在线观看| 亚洲综合图片小说区热久久| 中文字幕在线观看亚洲| 国产成人精品日本亚洲专区6| 亚洲私人无码综合久久网| 日本系列1页亚洲系列| 亚洲精品视频久久久| 国产亚洲精品a在线观看| 亚洲国产精品无码专区在线观看 |