成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:不會有人不懂類加載器與雙親委派模型吧?

開發 前端
類加載器在加載階段,會將class文件加載進方法區。有關類加載的全過程,可以先參考我的另外一篇文章類的奇幻漂流——類加載機制探秘

[[374028]]

 類加載器在加載階段,會將class文件加載進方法區。有關類加載的全過程,可以先參考我的另外一篇文章類的奇幻漂流——類加載機制探秘

類加載器的類型

類加載器有以下種類:

  • 啟動類加載器(Bootstrap ClassLoader)
  • 擴展類加載器(Extension ClassLoader)
  • 應用類加載器(Application ClassLoader)

啟動類加載器

內嵌在JVM內核中的加載器,由C++語言編寫(因此也不會繼承ClassLoader),是類加載器層次中最頂層的加載器。用于加載java的核心類庫,即加載jre/lib/rt.jar里所有的class。由于啟動類加載器涉及到虛擬機本地實現細節,我們無法獲取啟動類加載器的引用。

擴展類加載器

它負責加載JRE的擴展目錄,jre/lib/ext或者由java.ext.dirs系統屬性指定的目錄中jar包的類。父類加載器為啟動類加載器,但使用擴展類加載器調用getParent依然為null。

應用類加載器

又稱系統類加載器,可用通過 java.lang.ClassLoader.getSystemClassLoader()方法獲得此類加載器的實例,系統類加載器也因此得名。應用類加載器主要加載classpath下的class,即用戶自己編寫的應用編譯得來的class,調用getParent返回擴展類加載器。

擴展類加載器與應用類加載器繼承結構如圖所示:

面試官:不會有人不懂類加載器與雙親委派模型吧?

可以看到除了啟動類加載器,其余的兩個類加載器都繼承于ClassLoader,我們自定義的類加載,也需要繼承ClassLoader。

雙親委派機制

當一個類加載器收到了一個類加載請求時,它自己不會先去嘗試加載這個類,而是把這個請求轉交給父類加載器,每一個層的類加載器都是如此,因此所有的類加載請求都應該傳遞到最頂層的啟動類加載器中。只有當父類加載器在自己的加載范圍內沒有搜尋到該類時,并向子類反饋自己無法加載后,子類加載器才會嘗試自己去加載。

ClassLoader內的loadClass方法,就很好的解釋了雙親委派的加載模式:

  1. protected Class<?> loadClass(String name, boolean resolve) 
  2.       throws ClassNotFoundException 
  3.   { 
  4.       synchronized (getClassLoadingLock(name)) { 
  5.           //檢查該class是否已經被當前類加載器加載過 
  6.           Class<?> c = findLoadedClass(name); 
  7.           if (c == null) { 
  8.             //此時該class還沒有被加載 
  9.               try { 
  10.                   if (parent != null) { 
  11.                     //如果父加載器不為null,則委托給父類加載 
  12.                       c = parent.loadClass(namefalse); 
  13.                   } else { 
  14.                      //如果父加載器為null,說明當前類加載器已經是啟動類加載器,直接時候用啟動類加載器去加載該class 
  15.                       c = findBootstrapClassOrNull(name); 
  16.                   } 
  17.               } catch (ClassNotFoundException e) { 
  18.               } 
  19.  
  20.               if (c == null) { 
  21.                   //此時父類加載器都無法加載該class,則使用當前類加載器進行加載 
  22.                   long t1 = System.nanoTime(); 
  23.                   c = findClass(name); 
  24.                   ... 
  25.               } 
  26.           } 
  27.           //是否需要連接該類 
  28.           if (resolve) { 
  29.               resolveClass(c); 
  30.           } 
  31.           return c; 
  32.       } 
  33.   } 

 為什么要使用雙親委派機制,就使用當前的類加載器去加載不就行了嗎?為啥搞得這么復雜呢?

假設現在并沒有雙親委派機制,有這樣的一個場景:

用戶寫了一個Student類,點擊運行,此時編譯完成后,虛擬機開始加載class,該class會由應用加載器進行加載,由于Object類是Student的父類,且雙親委派機制不存在的情況下,應用加載器就會自己嘗試加載Object類,但是用戶壓根沒定義Object,即應用加載器無法在加載范圍搜尋到該類,所以此時Object類無法被加載,用戶寫的代碼無法運行。

假設該用戶自己定義了一個Object類,此時再次運行后,應用類加載器則會正常加載用戶定義的Object與Student類。Student類中會調用System.out.print()輸出Student對象,此時會由啟動類加載器加載System類,在此之前同樣也會加載Object類。

此時,方法區中有了兩份Object的元數據,Object類被重復加載了!

倘若用戶定義的Object類不安全,可能直接造成虛擬機崩潰或者引起重大安全問題。

如果現在使用雙親委派機制,用戶雖然自己定義了Object類,可以通過編譯,但是永遠不會被記載進方法區。

雙親委派機制避免了重復加載,也保證了虛擬機的安全。

自定義類加載器

我們整理ClassLoader里面的流程

  1. loadclass:判斷是否已加載,使用雙親委派模型,請求父加載器,父加載器反饋無法加載,因此使用findclass,讓當前類加載器查找
  2. findclass:當前類加載器根據路徑以及class文件名稱加載字節碼,從class文件中讀取字節數組,然后使用defineClass
  3. defineclass:根據字節數組,返回Class對象

我們在ClassLoader里面找到findClass方法,發現該方法直接拋出異常,應該是留給子類實現的。

  1. protected Class<?> findClass(String name) throws ClassNotFoundException { 
  2.       throw new ClassNotFoundException(name); 
  3.   } 

 到這里,我們應該明白,loadClass方法使用了模版方法模式,主線邏輯是雙親委派,但如何將class文件轉化為Class對象的步驟,已經交由子類去實現。對模版方法模式不熟悉的同學,可以先參考我的另外一篇文章模版方法模式

其實源碼中,已經有一個自定義類加載的樣例代碼,在注釋中:

  1. class NetworkClassLoader extends ClassLoader { 
  2.         String host; 
  3.         int port; 
  4.  
  5.         public Class findClass(String name) { 
  6.             byte[] b = loadClassData(name); 
  7.             return defineClass(name, b, 0, b.length); 
  8.         } 
  9.  
  10.         private byte[] loadClassData(String name) { 
  11.             // load the class data from the connection 
  12.             
  13.         } 
  14.     } 

 看得出來,如果我們需要自定義類加載器,只需要繼承ClassLoader,并且重寫findClass方法即可。

現在有一個簡單的樣例,class文件依然在文件目錄中:

  1. package com.yang.testClassLoader; 
  2.  
  3. import sun.misc.Launcher; 
  4.  
  5. import java.io.*; 
  6.  
  7. public class MyClassLoader extends ClassLoader { 
  8.  
  9.     /** 
  10.      * 類加載路徑,不包含文件名 
  11.      */ 
  12.     private String path; 
  13.  
  14.  
  15.     public MyClassLoader(String path) { 
  16.         super(); 
  17.         this.path = path; 
  18.     } 
  19.  
  20.     @Override 
  21.     protected Class<?> findClass(String name) throws ClassNotFoundException { 
  22.         byte[] bytes = getBytesFromClass(name); 
  23.         assert bytes != null
  24.         //讀取字節數組,轉化為Class對象 
  25.         return defineClass(name, bytes, 0, bytes.length); 
  26.     } 
  27.  
  28.     //讀取class文件,轉化為字節數組 
  29.     private byte[] getBytesFromClass(String name) { 
  30.         String absolutePath = path + "/" + name + ".class"
  31.         FileInputStream fis = null
  32.         ByteArrayOutputStream bos = null
  33.         try { 
  34.             fis = new FileInputStream(new File(absolutePath)); 
  35.             bos = new ByteArrayOutputStream(); 
  36.             byte[] temp = new byte[1024]; 
  37.             int len; 
  38.             while ((len = fis.read(temp)) != -1) { 
  39.                 bos.write(temp, 0, len); 
  40.             } 
  41.             return bos.toByteArray(); 
  42.         } catch (IOException e) { 
  43.             e.printStackTrace(); 
  44.         } finally { 
  45.             if (null != fis) { 
  46.                 try { 
  47.                     fis.close(); 
  48.                 } catch (IOException e) { 
  49.                     e.printStackTrace(); 
  50.                 } 
  51.             } 
  52.             if (null != bos) { 
  53.                 try { 
  54.                     bos.close(); 
  55.                 } catch (IOException e) { 
  56.                     e.printStackTrace(); 
  57.                 } 
  58.             } 
  59.         } 
  60.         return null
  61.     } 
  62.  
  63.     public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { 
  64.         MyClassLoader classLoader = new MyClassLoader("C://develop"); 
  65.         Class test = classLoader.loadClass("Student"); 
  66.         test.newInstance(); 
  67.     } 

 Student類:

  1. public class Student { 
  2.     public Student() { 
  3.         System.out.println("student classloader is" + this.getClass().getClassLoader().toString()); 
  4.     } 

 注意,這個Student類千萬不要加包名,idea報錯不管他即可,然后使用javac Student.java編譯該類,將生成的class文件復制到c://develop下即可。

運行MyClassLoader的main方法后,可以看到輸出:


看得出來,Student.class確實是被我們自定義的類加載器給加載了。

破壞雙親委派

從上面的自定義類加載器的內容中,我們應該可以猜到了,破壞雙親委派直接重寫loadClass方法就完事了。事實上,我們確實可以重寫loadClass方法,畢竟這個方法沒有被final修飾。雙親委派既然有好處,為什么jdk對loadClass開放重寫呢?這要從雙親委派引入的時間來看:

  • 雙親委派模型是在JDK1.2之后才被引入的,而類加載器和抽象類java.lang.ClassLoader則在JDK1.0時代就已經存在,面對已經存在的用戶自定義類加載器的實現代碼,Java設計者引入雙親委派模型時不得不做出一些妥協。在此之前,用戶去繼承java.lang.ClassLoader的唯一目的就是為了重寫loadClass()方法,jdk為了向前兼容,不得已開放對loadClass的重寫操作。

當然,也不止這一次對雙親委派模型的破壞,詳細的文章可以參考破壞雙親委派模型,里面提到了一個“線程上下文類加載器”,對這個不熟悉的同學可以參考真正理解線程上下文類加載器(多案例分析)(無法放鏈接,百度搜索)

我們經常用的Tomcat與jdbc,就破壞了雙親委派,礙于文章的篇幅與博主的水平,暫時不在這里討論破壞的原因,有興趣的同學可以參考這一篇文章JDBC、Tomcat為什么要破壞雙親委派模型?(無法放鏈接,百度搜索)

 

責任編輯:姜華 來源: 今日頭條
相關推薦

2025-04-07 04:25:00

JDBCAPI加載器

2023-12-06 12:11:43

類加載器雙親委派模型

2023-01-27 23:14:26

Go2兼容性Go1

2023-02-03 07:24:49

雙親委派模型

2022-07-26 19:06:16

Linux命令MacOS

2023-08-04 08:53:42

2009-04-17 15:24:20

人生撤銷耍賴

2019-03-25 08:47:43

京東騰訊高層

2024-02-20 08:13:35

類加載引用Class

2020-08-03 07:04:54

測試面試官應用程序

2025-07-01 07:41:37

Java類加載器雙親委派

2024-12-04 09:01:55

引導類加載器C++

2021-07-28 10:08:19

類加載代碼塊面試

2025-02-13 00:00:00

TCP網絡通信

2021-08-04 08:31:10

MySQL數據庫日志

2022-03-21 09:05:18

volatileCPUJava

2020-11-02 07:02:10

加載鏈接初始化

2020-06-22 08:16:16

哈希hashCodeequals

2021-09-07 11:20:02

binlogMySQL數據庫

2024-02-22 15:36:23

Java內存模型線程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 2020国产在线 | 超碰地址 | 国产乱码久久久久久一区二区 | 国产精品嫩草影院精东 | 亚洲欧美中文日韩在线v日本 | 三级免费av | 精品国产一区久久 | 亚洲永久在线 | 欧美国产91 | 国产精品国产精品国产专区不卡 | 国产精品成av人在线视午夜片 | 亚洲狠狠丁香婷婷综合久久久 | 国产精品美女久久久久久免费 | 国产成人一区二区三区 | 欧美精品一二区 | 国产高清在线观看 | 久久伊人免费视频 | 日本一区二区三区视频在线 | 色狠狠桃花综合 | 97久久精品午夜一区二区 | 精品国产乱码久久久久久丨区2区 | www.伊人.com| 久久亚洲国产 | 亚洲欧洲在线观看视频 | 国产欧美日韩久久久 | 色婷综合网 | 精品国产乱码久久久久久蜜臀 | 国产精品一区一区 | 欧美一区二区视频 | 国产女人第一次做爰毛片 | 成人福利在线观看 | 亚洲精品久久久久中文字幕欢迎你 | 日日碰狠狠躁久久躁婷婷 | 乱码av午夜噜噜噜噜动漫 | 日本一区二区三区精品视频 | 91天堂 | 国产亚洲一区二区三区在线 | 成人片免费看 | 成人毛片网站 | 欧美自拍网站 | 国产精品久久久久久久久久久久 |