受歡迎的網(wǎng)站開發(fā)西安網(wǎng)站建設(shè)哪家好

中文版見下圖:
1、概述類的加載器及類加載過程
1.1、類加載子系統(tǒng)的作用
????????類加載器子系統(tǒng)負(fù)責(zé)從文件系統(tǒng)或者網(wǎng)絡(luò)中加載Class文件,class文件在文件開頭有特定的文件標(biāo)識(shí)。ClassLoader只負(fù)責(zé)class文件的加載,至于它是否可以運(yùn)行,則由Execution Engine(執(zhí)行引擎)決定。
????????加載的類信息存放于一塊稱為方法區(qū)的內(nèi)存空間。除了類的信息外,方法區(qū)中還會(huì)存放運(yùn)行時(shí)常量池信息,可能還包括字符串字面量和數(shù)字常量(這部分常量信息是Class文件中常量池部分的內(nèi)存映射)
1.2、類加載器(ClassLoader)角色
- classfile存在于本地硬盤上, 可以理解為設(shè)計(jì)師畫在紙上的模板,而最終這個(gè)模板在執(zhí)行的時(shí)候是要加載到JVM當(dāng)中來,根據(jù)這個(gè)文件實(shí)例化出n個(gè)一模一樣的實(shí)例。
- classfile加載到JVM中, 被稱為DNA元數(shù)據(jù)模板, 放在方法區(qū)。
- 在.class文件->JVM->最終成為元數(shù)據(jù)模板,此過程就要一個(gè)運(yùn)輸工具(類裝載ClassLoader) ?扮演一個(gè)快遞員的角色。
1.3、類的加載過程


2、類的加載過程
2.1、Loading 階段
????????通過一個(gè)類的全限定名獲取定義此類的二進(jìn)制字節(jié)流;然后將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu);最終在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口。
加載 .class 文件的幾種方式:
- 從本地系統(tǒng)中直接加載
- 通過網(wǎng)絡(luò)獲取,典型場(chǎng)景:Web Applet
- 從zip壓縮包中讀取,成為日后jar、war格式的基礎(chǔ)
- 運(yùn)行時(shí)計(jì)算生成,使用最多的是:動(dòng)態(tài)代理技術(shù)
- 由其他文件生成,典型場(chǎng)景:JSP應(yīng)用
- 從專有數(shù)據(jù)庫中提取.class文件,比較少見
- 從加密文件中獲取,典型的防Class文件被反編譯的保護(hù)措施
特別注意:系統(tǒng)中出現(xiàn)大的實(shí)例就是從這個(gè)環(huán)節(jié)出現(xiàn)的。
2.2、Linking 階段
? ? ? ? Linking階段主要分為三部分,分別是驗(yàn)證(Verify)、準(zhǔn)備(Prepare)與解析(Resolve)三個(gè)環(huán)節(jié)。詳細(xì)說明如下:
- 驗(yàn)證(Verify):目的在于確保Class文件的字節(jié)流中包含信息符合當(dāng)前虛擬機(jī)要求即規(guī)范, 保證被加載類的正確性,不會(huì)危害虛擬機(jī)自身安全。主要包括四種驗(yàn)證,文件格式驗(yàn)證,元數(shù)據(jù)驗(yàn)證,字節(jié)碼驗(yàn)證,符號(hào)引用驗(yàn)證。
- 準(zhǔn)備(Prepare):為類變量分配內(nèi)存并且設(shè)置該類變量的默認(rèn)初始值,即零值。
- 這里不包含用final修飾的static, 因?yàn)閒inal在編譯的時(shí)候就會(huì)分配了, 準(zhǔn)備階段會(huì)顯式初始化;
- 這里不會(huì)為實(shí)例變量分配初始化,類變量會(huì)分配在方法區(qū)中,而實(shí)例變量是會(huì)隨著對(duì)象一起分配到Java堆中。
- 解析(Resolve):將常量池內(nèi)的符號(hào)引用轉(zhuǎn)換為直接引用的過程。事實(shí)上, 解析操作往往會(huì)伴隨著JVM在執(zhí)行完初始化之后再執(zhí)行。符號(hào)引用就是一組符號(hào)來描述所引用的目標(biāo)。符號(hào)引用的字面量形式明確定義在《java虛擬機(jī)規(guī)范》的class文件格式中。直接引用就是直接指向目標(biāo)的指針、相對(duì)偏移量或一個(gè)間接定位到目標(biāo)的句柄。解析動(dòng)作主要針對(duì)類或接口、字段、類方法、接口方法、方法類型等。對(duì)應(yīng)常量池中的CONSTANT_Class_Info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。
2.3、Initialization階段
????????初始化階段就是執(zhí)行類構(gòu)造器方法 <clinit>() 的過程。此方法不需定義,是javac編譯器自動(dòng)收集類中的所有類變量的賦值動(dòng)作和靜態(tài)代碼塊中的語句合并而來,也就是說當(dāng)類中沒有靜態(tài)代碼塊或類變量賦值時(shí)就沒有該方法:
????????構(gòu)造器方法中指令按語句在源文件中出現(xiàn)的順序執(zhí)行。關(guān)于如何查看該方法,可以根據(jù)以下示例方法查看。比如創(chuàng)建一個(gè)這么的類并生成字節(jié)碼文件:
? ? ? ? 隨后在電腦里安裝以下軟件后,雙擊打開指定的 Java 類字節(jié)碼文件,如下圖所示:
查看軟件下載
? ? ? ? 隨后在打開軟件的頁面里找到 Methods 目錄,展開可以查看到該類自動(dòng)生成的?<clinit>() 方法,詳見下圖:
? ? ? ? 此外這里在說明一個(gè)示例,是與平常編寫不一樣的例子。就是某個(gè)靜態(tài)變量的賦值在前面,聲明在后面的。就好比下面的實(shí)例:
package org.blnp.cn.demos.chapter01;/*** @ClassName org.blnp.cn.demos.chapter01.ClassInitTest* @Description <pre></pre>* @Author liaoyibin 2045165565@qq.com* @CreateDate 2023-12-19 21:22* @Version v1.01* @ModifyRecord <pre>* 版本 修改人 修改時(shí)間 修改內(nèi)容描述* ----------------------------------------------* 1.00 liaoyibin 2023-12-19 21:22 新建* ----------------------------------------------* </pre>*/
public class ClassInitTest {private static int num = 10;static {numbers = 30;}private static int numbers = 5;public static void main(String[] args) {System.out.println(ClassInitTest.num);System.out.println("numbers " + numbers);}
}
原因:原因也就是上文說的 “構(gòu)造器方法中指令按語句在源文件中出現(xiàn)的順序執(zhí)行”,因?yàn)樵?連接(Linking)過程的準(zhǔn)備(Prepare)階段時(shí),number變量就已經(jīng)被賦值為零值了;而當(dāng)進(jìn)入到初始化(Initialization)階段時(shí)被賦值為 “30” 了,當(dāng)程序按順序執(zhí)行到下文時(shí) number 變量最終被賦值為 5 了。
Linking? --> Prepare:number = 0 -->? initialization:number = 30? -->? number = 5
? ? ? ? 根據(jù)Java代碼可以得知 number 變量是先賦值成 30 在最后賦值成 5 的,此時(shí)我們通過工具查看重新生成的字節(jié)碼文件核對(duì)查看下,可以得知以下結(jié)果:
? ? ? ? 可以看到也是和預(yù)計(jì)的結(jié)果是一樣的。雖然在靜態(tài)代碼塊里可以對(duì)后聲明的變量進(jìn)行賦值,但是并不能調(diào)用,如果進(jìn)行調(diào)用的話將會(huì)提示以下錯(cuò)誤(Illegal forward reference:非法的前向引用)。
? ? ? ? 可能會(huì)疑問,那如果是這樣的話還有什么用?看下面示例就清楚了:
????????<clinit>()不同于類的構(gòu)造器。(關(guān)聯(lián):構(gòu)造器是虛擬機(jī)視角下的<init>())若該類具有父類,JVM會(huì)保證子類的<clinit>()執(zhí)行前,父類的<clinit>()已經(jīng)執(zhí)行完畢。虛擬機(jī)必須保證一個(gè)類的<clinit>()方法在多線程下被同步加鎖。也就是說 <clinit> 方法只會(huì)被執(zhí)行一次,比如下面這個(gè)示例:
package org.blnp.cn.demos.chapter01;/*** @ClassName org.blnp.cn.demos.chapter01.DeadThredTest* @Description <pre></pre>* @Author liaoyibin 2045165565@qq.com* @CreateDate 2023-12-25 22:49* @Version v1.01* @ModifyRecord <pre>* 版本 修改人 修改時(shí)間 修改內(nèi)容描述* ----------------------------------------------* 1.00 liaoyibin 2023-12-25 22:49 新建* ----------------------------------------------* </pre>*/
public class DeadThredTest {public static void main(String[] args) {Runnable run = () -> {System.out.println(Thread.currentThread().getName() + "開始");DeadThreads dead = new DeadThreads();System.out.println(Thread.currentThread().getName() + "結(jié)束");};Thread thread1 = new Thread(run, "線程1");Thread thread2 = new Thread(run, "線程2");thread1.start();thread2.start();}
}class DeadThreads {static {if (true){System.out.println(Thread.currentThread().getName() + " 初始化當(dāng)前類! ");while (true) {}}}
}
3、類加載器分類
3.1、引導(dǎo)類加載器(Bootstrap ClassLoader)
????????又叫啟動(dòng)類加載器(引導(dǎo)類加載器,Bootstrap ClassLoader)。這個(gè)類加載使用C/C++語言實(shí)現(xiàn)的,嵌套在JVM內(nèi)部;
????????Bootstrap ClassLoader用來加載Java的核心庫(JAVA_HOME/jre/lib/rt.jarbsun.boot.class.path路徑下的內(nèi)容),用于提供JVM自身需要的類;此外 Bootstrap ClassLoader并不繼承自java.lang.ClassLoader,它沒有父加載器;并且出于安全考慮,Bootstrap啟動(dòng)類加載器只加載包名為java、javax、sun等開頭的類;
package org.blnp.cn.demos.chapter01;import java.net.URL;/*** @ClassName org.blnp.cn.demos.chapter01.LoaderTest* @Description <pre></pre>* @Author liaoyibin 2045165565@qq.com* @CreateDate 2023-12-26 20:27* @Version v1.01* @ModifyRecord <pre>* 版本 修改人 修改時(shí)間 修改內(nèi)容描述* ----------------------------------------------* 1.00 liaoyibin 2023-12-26 20:27 新建* ----------------------------------------------* </pre>*/
public class LoaderTest {public static void main(String[] args) {System.out.println("\n**********啟動(dòng)類加載器**************");//獲取BootstrapClassLoader能夠加載的api的路徑URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();for (URL element : urLs) {System.out.println(element.toExternalForm());}//從上面的路徑中隨意選擇一個(gè)類,來看看他的類加載器是什么:引導(dǎo)類加載器ClassLoader classLoader = java.security.Provider.class.getClassLoader();System.out.println(classLoader);//null 引導(dǎo)類加載器是獲取不到的System.out.println("\n***********擴(kuò)展類加載器*************");String extDirs = System.getProperty("java.ext.dirs");for (String path : extDirs.split(";")) {System.out.println(path);}System.out.println("\n***********擴(kuò)展類加載器2*************");//獲取系統(tǒng)類加載器:輸出 => sun.misc.Launcher$AppClassLoader@18b4aac2ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);//獲取其上層,擴(kuò)展類加載器: => sun.misc.Launcher$ExtClassLoader@1b6d3586ClassLoader extClassLoader = systemClassLoader.getParent();System.out.println(extClassLoader);//在獲取它的上層,結(jié)果無法獲取到: nullClassLoader bootstrapClassLoader = extClassLoader.getParent();System.out.println(bootstrapClassLoader);//對(duì)于用戶創(chuàng)建的類來說,默認(rèn)使用的是系統(tǒng)類加載器: => sun.misc.Launcher$AppClassLoader@18b4aac2ClassLoader classLoader1 = LoaderTest.class.getClassLoader();System.out.println(classLoader1);//String 類使用的是引導(dǎo)類加載器進(jìn)行加載的(Java的核心類庫都是使用引導(dǎo)類加載器進(jìn)行加載的): =》 nullClassLoader classLoader2 = String.class.getClassLoader();System.out.println(classLoader2);}
}
3.2、自定義類加載器(User-Defined ClassLoader)
? ? ? ? 這里的自定義并非是說由開發(fā)人員自定義的類加載器。從概念上來講,自定義類加載器一般指的是程序中由開發(fā)人員自定義的一類類加載器,但是Java虛擬機(jī)規(guī)范卻沒有這么定義,而是將所有派生于抽象類 ClassLoader 的類加載器都劃分為自定義類加載器。
4、擴(kuò)展類與系統(tǒng)類加載器的使用
4.1、擴(kuò)展類加載器(Extension ClassLoader)
? ? ? ? 是通過 Java 語言編寫的,由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)。并派生于ClassLoader類,其父類加載器為啟動(dòng)類加載器。
????????從 java.ext.dirs 系統(tǒng)屬性所指定的目錄中加載類庫, 或從JDK的安裝目錄的 jre/lib/ext 子目錄(擴(kuò)展目錄) 下加載類庫。如果用戶創(chuàng)建的JAR放在此目錄下, 也會(huì)自動(dòng)由擴(kuò)展類加載器加載。
4.2、系統(tǒng)類加載器(應(yīng)用程序類加載器 - AppClassLoader)
????????也是java語言編寫,由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn),并派生于ClassLoader類;其父類加載器為擴(kuò)展類加載器。
????????它負(fù)責(zé)加載環(huán)境變量 classpath 或系統(tǒng)屬性 java.class.path 指定路徑下的類庫,該類加載是程序中默認(rèn)的類加載器,一般來說,Java應(yīng)用的類都是由它來完成加載。通過ClassLoader#getSystemClassLoader() 方法可以獲取到該類加載器。
4.3、用戶自定義類加載器
什么是用戶自定義類加載器?
????????在Java的日常應(yīng)用程序開發(fā)中, 類的加載幾乎是由上述3種類加載器相互配合執(zhí)行的,在必要時(shí),我們還可以自定義類加載器,來定制類的加載方式。
為什么要自定義類加載器?
- 隔離加載類
- 修改類加載的方式
- 擴(kuò)展加載源
- 防止源碼泄漏
用戶自定義類加載器的實(shí)現(xiàn)步驟?
1.開發(fā)人員可以通過繼承抽象類 java.lang.ClassLoader類的方式,實(shí)現(xiàn)自己的類加載器,以滿足一些特殊的需求
2.在JDK1.2之前,在自定義類加載器時(shí),總會(huì)去繼承ClassLoader類并重寫loadclass()方法,從而實(shí)現(xiàn)自定義的類加載類,但是在JDK1.2之后已不再建議用戶去覆蓋loadclass()方法,而是建議把自定義的類加載邏輯寫在findclass()方法中
3.在編寫自定義類加載器時(shí),如果沒有太過于復(fù)雜的需求,可以直接繼承URLClassLoader類,這樣就可以避免自己去編寫findclass()方法及其獲取字節(jié)碼流的方式,使自定義類加載器編寫更加簡(jiǎn)潔。
?
package org.blnp.cn.demos.chapter01;import java.io.FileNotFoundException;/*** @ClassName org.blnp.cn.demos.chapter01.CustomClassLoaders* @Description <pre>用戶自定義實(shí)現(xiàn)類加載器示例</pre>* @Author liaoyibin 2045165565@qq.com* @CreateDate 2023-12-27 23:03* @Version v1.01* @ModifyRecord <pre>* 版本 修改人 修改時(shí)間 修改內(nèi)容描述* ----------------------------------------------* 1.00 liaoyibin 2023-12-27 23:03 新建* ----------------------------------------------* </pre>*/
public class CustomClassLoaders extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {//從指定路徑中加載具體的類,以二進(jìn)制流的方式進(jìn)行讀取byte[] result = getClassFromCsutomPath(name);if (null == result) {throw new FileNotFoundException();}else {return defineClass(name,result,0,result.length);}}catch (FileNotFoundException e) {e.printStackTrace();}throw new ClassNotFoundException(name);}private byte[] getClassFromCsutomPath(String name){//todo 從自定義路徑中加載指定類return null;}public static void main(String[] args) {CustomClassLoaders classLoaders = new CustomClassLoaders();try {Class<?> oneTest = Class.forName("OneTest", true, classLoaders);Object instance = oneTest.newInstance();System.out.println(instance.getClass().getClassLoader());} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}
}
4.4、ClassLoader 的常用方法
????????ClassLoader類,它是一個(gè)抽象類,其后所有的類加載器都繼承自ClassLoader(不包括啟動(dòng)類加載器)
方法名稱 | 描述 |
getParent | 返回該類加載器的超類加載器 |
loadClass(String name) | 加載名稱為name的類,返回結(jié)果為java.lang.Class類的實(shí)例 |
findClass(String name) | 查找名稱為name的類,返回結(jié)果為java.lang.Class類的實(shí)例 |
findLoadedClass(String name) | 查找名稱為name的已經(jīng)被加載過的類,返回結(jié)果為java.lang.Class類的實(shí)例 |
defineClass(String name,byte[] b.int?off,int len) | 把字節(jié)數(shù)組b中的內(nèi)容轉(zhuǎn)換為一個(gè)Java類,返回結(jié)果為java.lang.Class類的實(shí)例 |
resolveClass(Class<?> c) | 連接指定的一個(gè)Java類 |
獲取 ClassLoader 的幾種方式:
方式一:獲取當(dāng)前類的 ClassLoader
clazz.getClassLoader()
方式二:獲取當(dāng)前線程上下文的ClassLoader
Thread.currentThread().getContextClassLoader()
方式三:獲取系統(tǒng)的classLoader
ClassLoader.getSystemClassLoader()
方式四:獲取調(diào)用者的classLoader
DriverManager.getCallerClassLoader()
完整示例代碼:
package org.blnp.cn.demos.chapter01;/*** @ClassName org.blnp.cn.demos.chapter01.ClassLoaderTest2* @Description <pre></pre>* @Author liaoyibin 2045165565@qq.com* @CreateDate 2023-12-27 23:30* @Version v1.01* @ModifyRecord <pre>* 版本 修改人 修改時(shí)間 修改內(nèi)容描述* ----------------------------------------------* 1.00 liaoyibin 2023-12-27 23:30 新建* ----------------------------------------------* </pre>*/
public class ClassLoaderTest2 {public static void main(String[] args) {try {//1.ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();System.out.println(classLoader);//2.ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();System.out.println(classLoader1);//3.ClassLoader classLoader2 = ClassLoader.getSystemClassLoader().getParent();System.out.println(classLoader2);} catch (ClassNotFoundException e) {e.printStackTrace();}}
}
5、雙親委派機(jī)制
5.1、工作原理
什么是雙親委派機(jī)制?
????????Java虛擬機(jī)對(duì)class文件采用的是按需加載的方式, 也就是說當(dāng)需要使用該類時(shí)才會(huì)將它的class文件加載到內(nèi)存生成class對(duì)象。而且加載某個(gè)類的class文件時(shí), Java虛擬機(jī)采用的是雙親委派模式, 即把請(qǐng)求交由父類處理,它是一種任務(wù)委派模式。
工作原理?
- 如果一個(gè)類加載器收到了類加載請(qǐng)求,它并不會(huì)自己先去加載,而是把這個(gè)請(qǐng)求委托給父類的加載器去執(zhí)行;
- 如果父類加載器還存在其父類加載器,則進(jìn)一步向上委托,依次遞歸,請(qǐng)求最終將到達(dá)頂層的啟動(dòng)類加載器;
- 如果父類加載器可以完成類加載任務(wù),就成功返回,倘若父類加載器無法完成此加載任務(wù),子加載器才會(huì)嘗試自己去加載,這就是雙親委派模式。
5.2、使用示例
package org.blnp.cn.demos.chapter01;/*** @ClassName org.blnp.cn.demos.chapter01.StringTaskTest* @Description <pre>雙親委派機(jī)制案例演示</pre>* @Author liaoyibin 2045165565@qq.com* @CreateDate 2023-12-27 23:46* @Version v1.01* @ModifyRecord <pre>* 版本 修改人 修改時(shí)間 修改內(nèi)容描述* ----------------------------------------------* 1.00 liaoyibin 2023-12-27 23:46 新建* ----------------------------------------------* </pre>*/
public class StringTaskTest {public static void main(String[] args) {String str = new String();System.out.println("雙親委派機(jī)制演示……");StringTaskTest taskTest = new StringTaskTest();System.out.println("taskTest.getClass().getClassLoader() = " +taskTest.getClass().getClassLoader());}
}
package java.lang;/*** @ClassName java.lang.String* @Description <pre></pre>* @Author liaoyibin 2045165565@qq.com* @CreateDate 2023-12-27 23:48* @Version v1.01* @ModifyRecord <pre>* 版本 修改人 修改時(shí)間 修改內(nèi)容描述* ----------------------------------------------* 1.00 liaoyibin 2023-12-27 23:48 新建* ----------------------------------------------* </pre>*/
public class String {static {System.out.println("我是自定義的,不合規(guī)案例演示對(duì)象!!");}
}
輸出結(jié)果:??
Connected to the target VM, address: '127.0.0.1:34703', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:34703', transport: 'socket'
雙親委派機(jī)制演示……
taskTest.getClass().getClassLoader() = sun.misc.Launcher$AppClassLoader@18b4aac2Process finished with exit code 0
? ? ? ? 根據(jù)輸出結(jié)果可以得知,Java 類的加載機(jī)制是向上進(jìn)行委托加載的。否則在當(dāng)前工程內(nèi)已有一個(gè)同包同名的類必然被加載訪問并輸出結(jié)果。但明顯是沒有,使用的是Java包的String類。
????????當(dāng)然,還有一個(gè)最簡(jiǎn)單的驗(yàn)證方式。那就是在自己定義的 String 方法里直接執(zhí)行 main 方法,結(jié)果如下所示:
5.3、優(yōu)勢(shì)
- 避免類的重復(fù)加載
- 保護(hù)程序安全,防止核心API被隨意篡改
6、沙箱安全機(jī)制
????????自定義string類,但是在加載自定義string類的時(shí)候會(huì)率先使用引導(dǎo)類加載器加載,而引導(dǎo)類加載器在加載的過程中會(huì)先加載jdk自帶的文件(rt.jar包中java\lang\string.class),報(bào)錯(cuò)信息說沒有main方法,就是因?yàn)榧虞d的是rt.jar包中的string類。這樣可以保證對(duì)java核心源代碼的保護(hù),這就是沙箱安全機(jī)制。
7、類的主動(dòng)使用與被動(dòng)使用
7.1、前言
????????在JVM中表示兩個(gè)class對(duì)象是否為同一個(gè)類存在兩個(gè)必要條件:
- 類的完整類名必須一致,包括包名。
- 加載這個(gè)類的ClassLolader (指ClassLoader實(shí)例對(duì)象)必須相同。
????????換句話說,在JVM中,即使這兩個(gè)類對(duì)象(class對(duì)象)來源同一個(gè)Class文件,被同一個(gè)虛擬機(jī)所加載,但只要加載它們的ClassLoader實(shí)例對(duì)象不同,那么這兩個(gè)類對(duì)象也是不相等的。
7.2、對(duì)類加載器的引用
????????JVM必須知道一個(gè)類型是由啟動(dòng)加載器加載的還是由用戶類加載器加載的。如果一個(gè)類型是由用戶類加載器加載的,那么JVM會(huì)將這個(gè)類加載器的一個(gè)引用作為類型信息的一部分保存在方法區(qū)中。當(dāng)解析一個(gè)類型到另一個(gè)類型的引用的時(shí)候,JVM需要保證這兩個(gè)類型的類加載器是相同的。
7.3、主動(dòng)使用 & 被動(dòng)使用
? ? ? ? Java程序?qū)︻惖氖褂梅绞椒譃?#xff1a;主動(dòng)使用和被動(dòng)使用。主動(dòng)使用又分為七種情況:
- 創(chuàng)建類的實(shí)例
- 訪問某個(gè)類或接口的靜態(tài)變量,或者對(duì)該靜態(tài)變量賦值
- 調(diào)用類的靜態(tài)方法
- 反射(比如: Class.forName("com.atguigu.Test"))
- 初始化一個(gè)類的子類
- Java虛擬機(jī)啟動(dòng)時(shí)被標(biāo)明為啟動(dòng)類的類
- JDK 7 開始提供的動(dòng)態(tài)語言支持:java.lang.invoke.MethodHandle實(shí)例的解析結(jié)果REF_getstatic、 REF_putStatic、 REF_invokeStatic句柄對(duì)應(yīng)的類沒有初始化,則初始化
????????除了以上七種情況,其他使用Java類的方式都被看作是對(duì)類的被動(dòng)使用,都不會(huì)導(dǎo)致類的初始化。???????