自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

小米二面:JVM 觸發(fā)類加載的條件有哪些?我說 new 的時(shí)候加載,然后他對我笑了笑......

開發(fā) 前端
在本節(jié)中,我們將詳細(xì)探討類加載的時(shí)機(jī)、主動(dòng)和被動(dòng)引用的區(qū)別,以及常見的類加載觸發(fā)條件。

Java 虛擬機(jī)(JVM)中,類的加載并不是隨意發(fā)生的,而是由特定的觸發(fā)條件決定的。什么時(shí)候加載?什么時(shí)候初始化?

這是我們必須要搞清楚的問題,尤其在復(fù)雜的應(yīng)用中,弄懂類加載的時(shí)機(jī)能幫助我們避免一些潛在的性能問題和運(yùn)行時(shí)錯(cuò)誤。

在本節(jié)中,我們將詳細(xì)探討類加載的時(shí)機(jī)、主動(dòng)和被動(dòng)引用的區(qū)別,以及常見的類加載觸發(fā)條件。

類加載生命周期

類加載的生命周期包括:加載(Loading)、鏈接(Linking) 和 初始化(Initialization)。而其中,初始化階段是決定類是否被真正加載的關(guān)鍵。

JVM 在什么時(shí)候啟動(dòng)類加載過程呢?

主要分為主動(dòng)引用被動(dòng)引用兩種情況。我們分別看看這兩種情況在什么條件下會(huì)觸發(fā)類加載。

主動(dòng)引用

主動(dòng)引用是指程序顯式地使用某個(gè)類,從而觸發(fā)類的加載和初始化。根據(jù)《Java 虛擬機(jī)規(guī)范》,以下六種情況會(huì)觸發(fā)類的主動(dòng)引用,也就是觸發(fā)類加載的條件!

1. 創(chuàng)建類的實(shí)例

當(dāng)你使用 new 關(guān)鍵字創(chuàng)建一個(gè)類的實(shí)例時(shí),JVM 會(huì)立即加載并初始化該類。

// 觸發(fā) MyClass 的加載和初始化
MyClass obj = new MyClass();

初始化流程:

  • 分配內(nèi)存給 MyClass 的實(shí)例對象。
  • 加載 MyClass 類的字節(jié)碼,并執(zhí)行靜態(tài)代碼塊和靜態(tài)變量賦值操作。

2. 訪問類的靜態(tài)字段或靜態(tài)方法

訪問類的靜態(tài)字段或靜態(tài)方法時(shí),也會(huì)觸發(fā)類的加載和初始化。

// 觸發(fā) MyClass 的加載
System.out.println(MyClass.staticVar);  
// 觸發(fā) MyClass 的加載
MyClass.staticMethod();

常量不會(huì)觸發(fā)類加載:如果靜態(tài)字段是 final 修飾的常量,它在編譯期已存入常量池,因此不會(huì)觸發(fā)類加載。

System.out.println(MyClass.FINAL_CONSTANT);  // 不觸發(fā)類加載

3. 反射

通過反射調(diào)用類時(shí),也會(huì)觸發(fā)類加載。

Class<?> clazz = Class.forName("com.example.MyClass");  // 觸發(fā) MyClass 的加載

4. 初始化類的子類時(shí),先初始化父類

當(dāng)初始化一個(gè)類時(shí),如果它的父類尚未初始化,JVM 會(huì)先初始化父類。

public class Parent {
    static {
        System.out.println("父類初始化");
    }
}

public class Child extends Parent {
    static {
        System.out.println("子類初始化");
    }
}

// 先輸出"父類初始化",再輸出"子類初始化"
Child obj = new Child();

5. 擬機(jī)啟動(dòng)時(shí),初始化 main 方法所在的類

虛擬機(jī)啟動(dòng)時(shí),main 方法所在的類是程序的入口類,會(huì)被優(yōu)先加載和初始化。

public static void main(String[] args) {
    System.out.println("主類加載");
}

6. 動(dòng)態(tài)語言支持

在 Java 7 引入的 java.lang.invoke 包中,當(dāng) MethodHandle 最終指向的類需要初始化時(shí),也會(huì)觸發(fā)類的加載。

MethodHandle handle = MethodHandles.lookup().findStatic(MyClass.class, "staticMethod", MethodType.methodType(void.class));
handle.invoke();  // 可能觸發(fā) MyClass 的加載

被動(dòng)引用:不觸發(fā)類加載

與主動(dòng)引用相對,被動(dòng)引用是指訪問類的某些特性時(shí)不會(huì)觸發(fā)類的加載和初始化。以下是幾種典型的被動(dòng)引用場景。

1. 通過子類引用父類的靜態(tài)字段

如果子類只引用父類的靜態(tài)字段,JVM 只會(huì)初始化父類,而不會(huì)初始化子類。

示例

// 只觸發(fā) Parent 的加載,不觸發(fā) Child 的加載
System.out.println(Child.staticVar);

2. 訪問編譯期常量

訪問 final 修飾的編譯期常量,不會(huì)觸發(fā)類的加載。

// 不觸發(fā) MyClass 的加載
System.out.println(MyClass.FINAL_CONSTANT);

3. 通過數(shù)組定義類引用

通過數(shù)組引用一個(gè)類,不會(huì)觸發(fā)該類的加載。

// 不觸發(fā) MyClass 的加載
MyClass[] array = new MyClass[10];

碼哥,為什么需要關(guān)注類加載的時(shí)機(jī)?

  • 避免類的過早加載:過早加載可能導(dǎo)致不必要的內(nèi)存消耗,尤其在大型應(yīng)用中。
  • 延遲加載(Lazy Loading):通過延遲加載,可以在真正需要時(shí)才加載類,減少啟動(dòng)時(shí)間。
  • 減少類加載沖突:在模塊化或插件化的應(yīng)用中,合理安排類加載順序有助于避免類沖突和類加載死鎖問題。
責(zé)任編輯:姜華 來源: 碼哥跳動(dòng)
相關(guān)推薦

2024-03-26 07:58:12

Redis編程模型

2025-01-14 08:32:55

2021-05-19 08:31:15

壓測數(shù)據(jù)結(jié)構(gòu)與算法工具

2020-07-23 07:26:49

JVM類加載器

2024-07-08 10:11:37

2024-03-08 08:26:25

類的加載Class文件Java

2024-12-04 09:01:55

引導(dǎo)類加載器C++

2021-05-08 09:02:19

Java加載器

2012-03-13 14:41:41

JavaJVM

2024-03-12 07:44:53

JVM雙親委托機(jī)制類加載器

2023-10-31 16:00:51

類加載機(jī)制Java

2017-09-20 08:07:32

java加載機(jī)制

2021-04-29 11:18:14

JVM加載機(jī)制

2017-03-08 10:30:43

JVMJava加載機(jī)制

2024-12-02 09:01:23

Java虛擬機(jī)內(nèi)存

2024-04-22 00:00:00

CASCPU硬件

2017-09-22 15:25:40

Go語言其他語言錯(cuò)誤處理

2010-03-08 08:39:54

類加載器newJava

2015-07-03 10:12:41

小米迅雷

2020-02-11 13:22:20

this函數(shù)JavaScript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)