摘要:比如我們要加載類,無論我們用哪個(gè)類加載器去加載類,這個(gè)加載請(qǐng)求最終都會(huì)委托給,這樣就保證了所有加載器加載的類都是同一個(gè)類。如果沒有雙親委派模型,那就亂了套了,完全可能搞出多個(gè)不同的類。
前言
雙親委派模型是Java加載類的機(jī)制.采用雙親委派模型的好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層級(jí)關(guān)系,通過這種層級(jí)關(guān)系可以避免類的重復(fù)加載.
1. 模型基礎(chǔ)Bootstrap ClassLoader(啟動(dòng)類加載器): 負(fù)責(zé)將%JAVA_HOME%/lib目錄中或-Xbootclasspath中參數(shù)指定的路徑中的,并且是虛擬機(jī)識(shí)別的(按名稱)類庫加載到JVM中
Extension ClassLoader(擴(kuò)展類加載器): 負(fù)責(zé)加載%JAVA_HOME%/lib/ext中的所有類庫
Application ClassLoader(應(yīng)用程序加載器): 負(fù)責(zé)ClassPath中的類庫
2. 為什么使用雙親委派模型?1.雙親委派模型最大的好處就是讓Java類同其類加載器一起具備了一種帶優(yōu)先級(jí)的層次關(guān)系。這句話可能不好理解,我們舉個(gè)例子。比如我們要加載java.lang.Object類,無論我們用哪個(gè)類加載器去加載Object類,這個(gè)加載請(qǐng)求最終都會(huì)委托給Bootstrap ClassLoader,這樣就保證了所有加載器加載的Object類都是同一個(gè)類。如果沒有雙親委派模型,那就亂了套了,完全可能搞出多個(gè)不同的Object類。
2.自上而下每個(gè)類加載器都會(huì)盡力加載.
1.首先加載類調(diào)用的loadClass方法,我們找到ClassLoader的loadClass():
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; } }
首先判斷了該類是否已加載.
若沒加載,則傳給雙親加載器去加載,
若雙親加載器沒能成功加載它,則自己用findClass()去加載.所以是個(gè)向上遞歸的過程.
自定義加載器時(shí),需要重寫findClass方法,因?yàn)槭强盏?沒有任何內(nèi)容:
protected Class> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }4. 自己動(dòng)手,編寫一個(gè)自己的類加載器
1.首先需要一個(gè)編譯好的class文件,筆者用了一個(gè)之前寫的斐波那契的類Fib.class(所在路徑:C:/Users/Think/crabapple),下面是用idea通過反編譯方式打開的class文件,注意記下class文件的包名,在后續(xù)代碼中需要使用類的全限定名稱.
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package crabapple; public class Fib { public static int fib(int num) { return num < 2 ? num : fib(num - 2) + fib(num - 1); } }
2.繼承ClassLoader,重寫findClass方法:
class MyClassLoader extends ClassLoader { private String classPath; // 保存的地址 /** * 傳入地址構(gòu)造函數(shù) * @param classPath */ public MyClassLoader(String classPath) { this.classPath = classPath; } /** * 讀取class文件 * @param name * @return * @throws Exception */ private byte[] loadByte(String name) throws Exception { String inPath = classPath + "/" + name + ".class"; FileInputStream fis = new FileInputStream(inPath); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } /** * 重寫findClass方法,讓加載的時(shí)候調(diào)用findClass方法 * @param name * @return * @throws ClassNotFoundException */ protected Class> findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); // 將字節(jié)碼載入內(nèi)存 return defineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); } return null; } }
loadByte方法僅用作讀取文件
findClass方法才是加載類到內(nèi)存的,注意name必須填全限定名,比如java.lang.Object.
3.測(cè)試,一下將使用一些反射機(jī)制和class類的方法.
public class ClassLoaderTest extends ClassLoader { //main函數(shù)本該拋出異常有 ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException,為了好看,簡寫成Exception public static void main(String[] args) throws Exception { //初始化類加載器 MyClassLoader myClassLoader=new MyClassLoader("C:/Users/Think/crabapple"); //加載Fib類,筆者class文件包名為crabapple Class myClass=myClassLoader.loadClass("crabapple.Fib"); //獲取加載類的實(shí)例 Object object=myClass.newInstance(); //獲取該類一個(gè)名為fib,且參數(shù)為int的方法 Method method=myClass.getMethod("fib",int.class); //執(zhí)行這個(gè)方法 int result=method.invoke(object,4); //打印結(jié)果 System.out.print(result); //output /** * 3 * Process finished with exit code 0 */ } }
執(zhí)行成功
我們來分析下,Fib類的加載過程,初始化自定義類加載器后,loadClass方法肯定將其委派到雙親Application ClassLoader,而Application ClassLoader又將其委派到Extension ClassLoader,繼而委派到Bootstrap ClassLoader.但是Bootstrap ClassLoader發(fā)現(xiàn)Fib并不在自己的加載能力范圍內(nèi),于是移向Extension ClassLoader,同理Extension ClassLoader只能加載/ext中的class,繼而讓給Application ClassLoader,而Application ClassLoader只加載classpath中的類,于是又回到我們自定義的MyClassLoader,幸好我們重寫了findClass方法進(jìn)而執(zhí)行了加載,否在findClass拋出找不到類的異常.至此Fib類加載完成.
結(jié)語如上便是筆者對(duì)雙親委派模型的總結(jié),如有錯(cuò)誤,歡迎指正.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/73936.html
摘要:最終形成可以被虛擬機(jī)最直接使用的類型的過程就是虛擬機(jī)的類加載機(jī)制。即重寫一個(gè)類加載器的方法驗(yàn)證驗(yàn)證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。 《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐(第二版》讀書筆記與常見相關(guān)面試題總結(jié) 本節(jié)常見面試題(推薦帶著問題閱讀,問題答案在文中都有提到): 簡單說說類加載過...
摘要:虛擬機(jī)為了保證一個(gè)類的方法在多線程環(huán)境中被正確地加鎖同步。但啟動(dòng)類加載器不可能認(rèn)識(shí)這些代碼。實(shí)現(xiàn)模塊化熱部署的關(guān)鍵則是它的自定義類加載器機(jī)制的實(shí)現(xiàn)。 概念區(qū)分:加載、類加載、類加載器 類加載是一個(gè)過程。 加載(Loading)是類加載這一個(gè)過程的階段。 類加載器是ClassLoader類或其子類。 本文中的類的描述都包括了類和接口的可能性,因?yàn)槊總€(gè)Class文件都有可能代表J...
摘要:如果需要支持類的動(dòng)態(tài)加載或需要對(duì)編譯后的字節(jié)碼文件進(jìn)行解密操作等,就需要與類加載器打交道了。雙親委派模型,雙親委派模型,約定類加載器的加載機(jī)制。任何之類的字節(jié)碼都無法調(diào)用方法,因?yàn)樵摲椒ㄖ荒茉陬惣虞d的過程中由調(diào)用。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級(jí)算法 GC策略的評(píng)價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card table數(shù)據(jù)...
摘要:驗(yàn)證驗(yàn)證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。字節(jié)碼驗(yàn)證通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的符合邏輯的。 看過這篇文章,大廠面試你「雙親委派模型」,硬氣的說一句,你怕啥? 讀該文章姿勢(shì) 打開手頭的 IDE,按照文章內(nèi)容及思路進(jìn)行代碼跟蹤與思考 手頭沒有 IDE,先收藏,回頭看 (萬一哪次面試問...
摘要:類加載過程雙親委派模型聲明文章均為本人技術(shù)筆記,轉(zhuǎn)載請(qǐng)注明出處類加載過程類加載機(jī)制將類描述數(shù)據(jù)從文件中加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行,解析和初始化,最終形成被直接使用的類型。深入理解虛擬機(jī)高級(jí)特性與最佳實(shí)踐加載加載階段由類加載器負(fù)責(zé),過程見類加載 JVM類加載過程 & 雙親委派模型 聲明 文章均為本人技術(shù)筆記,轉(zhuǎn)載請(qǐng)注明出處https://segmentfault.com/u/yzwall ...
閱讀 2325·2021-11-23 10:09
閱讀 2894·2021-10-12 10:11
閱讀 2601·2021-09-29 09:35
閱讀 1343·2019-08-30 15:53
閱讀 2269·2019-08-30 11:15
閱讀 2915·2019-08-29 13:01
閱讀 2298·2019-08-28 18:15
閱讀 3369·2019-08-26 12:13