#當我們要使用一個類別的時候,要透過ClassLoader將類別載入到記憶體中
「類別載入階段主要完成以下三件事情」
「透過全類別名,取得類別的二進位流的方式有很多種”
#「對於非陣列類型的載入階段,也就是可以使用Java虛擬機器內建的類別載入器去完成,也可以使用使用者自訂的類別載入器去完成”
「連結這個階段主要分為3個部分,驗證,準備,解析」
#「驗證階段主要是確保Class檔案的格式正確,運行時不會危害虛擬機器的安全」
驗證階段的規則很多,但大致分為如下4個階段「具體詳細的內容,我就不詳細解釋了,可以看《深入理解Java虛擬機》,本篇文章偏向於做一個總結,把握類別加載的一個整體流程,而不對細節進行闡述”
「準備階段主要是為類別的靜態變數分配內存,並將其初始化為默認值”
常見的資料類型的預設值如下
資料型別 | 預設值 |
---|---|
byte | # (byte)0 |
short | (short)0 |
int | #0 |
long | 0L |
float | 0.0f |
#double | 0.0d |
boolean | false |
char | '\u0000' |
#參考 | null |
「如果類別靜態變數的欄位屬性表中存在ConstantValue屬性,則直接執行賦值語句」
那麼什麼情況下類別靜態變數的欄位屬性表中存在ConstantValue屬性呢?
為了方便查看Class檔案的字節碼,我在IDEA下載了一個外掛程式jclasslib Bytecode viewer,非常方便。用以下程式碼透過字節碼的形式驗證一下
public class Person { private static int age = 10; private static final int length = 160; private static final String name = "name"; private static final String loc = new String("loc"); }
「所以length和name屬性在準備階段就會賦值為ConstantValue指定的值」
#「那麼age和loc屬性會在哪個階段賦值呢?是在初始化階段,後面會詳細介紹哈」
「將類,接口,字段和方法的符號引用(在常數池中)轉為直接引用」符號引用:用一組符號來描述所引用的目標 直接引用;直接指向指向目標的指標
加入我寫了一個如下的類別public class Student { private String name; private int age; public String getName() { return this.name; } }
以欄位為例,name和age對應的物件並不是直接指向記憶體位址,而是用字串來進行描述(即符號引用)。解析階段就是將這些描述轉為直接指向目標的指標(即直接引用)
「执行类静态成员变量赋值语句和静态代码块中的语句」
我们把上面的Student代码改成如下形式
public class Student { private String name; private int age = 10; private static int gender = 1; { System.out.println("构造代码块"); } static { System.out.println("静态代码块"); } public Student() { System.out.println("构造函数"); } public String getName() { return this.name; } }
可以看到字节码中包含了3个方法,getName方法我们知道,
「
从字节码可以看到
「
「理解
「有繼承情況的執行順序」
#########父類別的靜態(靜態程式碼區塊,靜態成員變數),子類別的靜態(靜態程式碼區塊,靜態成員變數)(只會執行一次哈)############父類別的非靜態(構造程式碼區塊,非靜態成員變數),父類別的建構子############子類別的非靜態(建構程式碼區塊,非靜態成員變數),子類別的建構子### ##################卸載################垃圾收集不只發生在堆中,方法區上也會發生。但是對方法區的型別資料回收的條件比較嚴苛######以下圖為例,想回收方法區中的Simple類別###可以看到對方法區的類型資料回收的條件比較苛刻,但是收效甚微,所以有些垃圾收集器不會對方法區的類型資料進行回收
類別載入過程
變數的賦值過程
以上是面試官:說一下類別載入的過程(10張圖解)的詳細內容。更多資訊請關注PHP中文網其他相關文章!