java类加载器_类加载器
回顧一下類(lèi)加載過(guò)程
類(lèi)加載過(guò)程:加載->連接->初始化。連接過(guò)程又可分為三步:驗(yàn)證->準(zhǔn)備->解析。
一個(gè)非數(shù)組類(lèi)的加載階段(加載階段獲取類(lèi)的二進(jìn)制字節(jié)流的動(dòng)作)是可控性最強(qiáng)的階段,這一步我們可以去完成還可以自定義類(lèi)加載器去控制字節(jié)流的獲取方式(重寫(xiě)一個(gè)類(lèi)加載器的 loadClass() 方法)。數(shù)組類(lèi)型不通過(guò)類(lèi)加載器創(chuàng)建,它由 Java 虛擬機(jī)直接創(chuàng)建。
所有的類(lèi)都由類(lèi)加載器加載,加載的作用就是將 .class文件加載到內(nèi)存。
類(lèi)加載器總結(jié)
JVM 中內(nèi)置了三個(gè)重要的 ClassLoader,除了 BootstrapClassLoader 其他類(lèi)加載器均由 Java 實(shí)現(xiàn)且全部繼承自java.lang.ClassLoader:
雙親委派模型
雙親委派模型介紹
每一個(gè)類(lèi)都有一個(gè)對(duì)應(yīng)它的類(lèi)加載器。系統(tǒng)中的 ClassLoder 在協(xié)同工作的時(shí)候會(huì)默認(rèn)使用 雙親委派模型 。即在類(lèi)加載的時(shí)候,系統(tǒng)會(huì)首先判斷當(dāng)前類(lèi)是否被加載過(guò)。已經(jīng)被加載的類(lèi)會(huì)直接返回,否則才會(huì)嘗試加載。加載的時(shí)候,首先會(huì)把該請(qǐng)求委派該父類(lèi)加載器的 loadClass() 處理,因此所有的請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類(lèi)加載器 BootstrapClassLoader 中。當(dāng)父類(lèi)加載器無(wú)法處理時(shí),才由自己來(lái)處理。當(dāng)父類(lèi)加載器為null時(shí),會(huì)使用啟動(dòng)類(lèi)加載器 BootstrapClassLoader 作為父類(lèi)加載器。
每個(gè)類(lèi)加載都有一個(gè)父類(lèi)加載器,我們通過(guò)下面的程序來(lái)驗(yàn)證。
public class ClassLoaderDemo {public static void main(String[] args) {System.out.println("ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader());System.out.println("The Parent of ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader().getParent());System.out.println("The GrandParent of ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader().getParent().getParent());} }Output
ClassLodarDemo's ClassLoader is sun.misc.Launcher$AppClassLoader@18b4aac2 The Parent of ClassLodarDemo's ClassLoader is sun.misc.Launcher$ExtClassLoader@1b6d3586 The GrandParent of ClassLodarDemo's ClassLoader is nullAppClassLoader的父類(lèi)加載器為ExtClassLoader ExtClassLoader的父類(lèi)加載器為null,null并不代表ExtClassLoader沒(méi)有父類(lèi)加載器,而是 BootstrapClassLoader 。
其實(shí)這個(gè)雙親翻譯的容易讓別人誤解,我們一般理解的雙親都是父母,這里的雙親更多地表達(dá)的是“父母這一輩”的人而已,并不是說(shuō)真的有一個(gè) Mother ClassLoader 和一個(gè) Father ClassLoader 。另外,類(lèi)加載器之間的“父子”關(guān)系也不是通過(guò)繼承來(lái)體現(xiàn)的,是由“優(yōu)先級(jí)”來(lái)決定。官方API文檔對(duì)這部分的描述如下:
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.雙親委派模型實(shí)現(xiàn)源碼分析
雙親委派模型的實(shí)現(xiàn)代碼非常簡(jiǎn)單,邏輯非常清晰,都集中在 java.lang.ClassLoader 的 loadClass() 中,相關(guān)代碼如下所示。
private final ClassLoader parent; protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// 首先,檢查請(qǐng)求的類(lèi)是否已經(jīng)被加載過(guò)Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {//父加載器不為空,調(diào)用父加載器loadClass()方法處理c = parent.loadClass(name, false);} else {//父加載器為空,使用啟動(dòng)類(lèi)加載器 BootstrapClassLoader 加載c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//拋出異常說(shuō)明父類(lèi)加載器無(wú)法完成加載請(qǐng)求}if (c == null) {long t1 = System.nanoTime();//自己嘗試加載c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}雙親委派模型的好處
雙親委派模型保證了Java程序的穩(wěn)定運(yùn)行,可以避免類(lèi)的重復(fù)加載(JVM 區(qū)分不同類(lèi)的方式不僅僅根據(jù)類(lèi)名,相同的類(lèi)文件被不同的類(lèi)加載器加載產(chǎn)生的是兩個(gè)不同的類(lèi)),也保證了 Java 的核心 API 不被篡改。如果沒(méi)有使用雙親委派模型,而是每個(gè)類(lèi)加載器加載自己的話(huà)就會(huì)出現(xiàn)一些問(wèn)題,比如我們編寫(xiě)一個(gè)稱(chēng)為 java.lang.Object 類(lèi)的話(huà),那么程序運(yùn)行的時(shí)候,系統(tǒng)就會(huì)出現(xiàn)多個(gè)不同的 Object 類(lèi)。
如果我們不想用雙親委派模型怎么辦?
為了避免雙親委托機(jī)制,我們可以自己定義一個(gè)類(lèi)加載器,然后重寫(xiě) loadClass() 即可。
完善修正(issue871:類(lèi)加載器一問(wèn)的補(bǔ)充說(shuō)明):
自定義加載器的話(huà),需要繼承 ClassLoader 。如果我們不想打破雙親委派模型,就重寫(xiě) ClassLoader 類(lèi)中的 findClass() 方法即可,無(wú)法被父類(lèi)加載器加載的類(lèi)最終會(huì)通過(guò)這個(gè)方法被加載。但是,如果想打破雙親委派模型則需要重寫(xiě) loadClass() 方法
自定義類(lèi)加載器
除了 BootstrapClassLoader 其他類(lèi)加載器均由 Java 實(shí)現(xiàn)且全部繼承自java.lang.ClassLoader。如果我們要自定義自己的類(lèi)加載器,很明顯需要繼承 ClassLoader。
推薦閱讀
- 深入分析Java ClassLoader原理
- 《2020最新Java基礎(chǔ)精講視頻教程和學(xué)習(xí)路線(xiàn)!》
- 老大難的 Java ClassLoader 再不理解就老了
- Java類(lèi)加載器(ClassLoader)
鏈接:類(lèi)加載器
來(lái)源:github
總結(jié)
以上是生活随笔為你收集整理的java类加载器_类加载器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: music算法_“要热爱 请深爱”系列(
- 下一篇: nofollow标签_如何Nofollo