title: JVM之類的加載、連接與初始化
date: 2019-04-01
tags: java
JVM之類的加載、連接與初始化——2019-04-01
- 加載:查找並加載類的二進制數據
- 連接
- 驗證:確保被加載類的正確性
- 準備:爲類的靜態變量分配內存,並將其初始化爲默認值
- 解析:把類中的符號引用轉換爲直接引用
- 初始化:爲類的靜態變量賦予正確的初始值
如:
Class test{
Public static int a=1;
}
在test類在被加載時,靜態變量a首先被分配內存,設置默認值a=0
接着在初始化過程中才被賦予正確的初始值a=1
Java程序對類的使用方式可分爲兩種
主動使用
被動使用
所有的Java虛擬機實現必須在每個類或接口被Java程序“首次主動使用”時才能初始化他們
主動使用(七種)
創建類的實例(new一個類對象)
訪問某個類或接口的靜態變量,或者對該靜態變量賦值(對靜態變量取值賦值)
助記符 getstatic putstatic
調用類的靜態方法 助記符 invokestatic
反射(如Class.forName(“com.test.Test”))
初始化一個類的子類
如:
Class Parent{}
Class Child extends Parent{}
當子類被初始化時,同時也標記着父類的主動使用,父類也會被初始化
Java虛擬機啓動時被標明爲啓動類的類(Java Test)
JDK1.7開始提供的動態語言支持
Java.lang.invoke.MethodHandle實例的解析結果REF_getStatic, REF_putStatic, REF_invokeStatic句柄對應的類沒有初始化,則初始化
除了以上七種情況,其它使用java類的方式都被看作是對類的被動使用,都不會導致類的初始化
類的加載
類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後在內存中創建一個java.lang.Class對象(規範並未說明Class對象位於哪裏,大致上放在堆區,HotSpot虛擬機將其放在了方法區中)用來封裝類在方法區內的數據結構
加載.class文件的方式
從本地系統中直接加載(ide工作區重啓加載項目即是如此)
通過網絡下載.class文件
從zip,jar等歸檔文件中加載.class文件
從專有數據庫中提取.class文件
將Java源文件動態編譯爲.class文件(如JSP中java代碼的編寫,實際上是轉化成了Servlet)
(主動使用)
測試代碼一
package com.lagoon.jvm.classloder;
public class MyTest1 {
public static void main(String[] args) {
System.out.println(MyChild1.str);
}
}
class MyParent1{
public static String str="hello world";
static {
System.out.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1{
static {
System.out.println("MyChild1 static block");
}
}
測試結果
並沒有輸出MyChild1 static block
這種情況稱之爲對MyParent1的一個主動使用,但是並沒有對MyChild1進行主動使用
所以並不會對MyChild1進行初始化,也就不會執行靜態代碼塊
測試代碼二
package com.lagoon.jvm.classloder;
public class MyTest1 {
public static void main(String[] args) {
System.out.println(MyChild1.str2);
}
}
class MyParent1{
public static String str="hello world";
static {
System.out.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1{
public static String str2="welcome...";
static {
System.out.println("MyChild1 static block");
}
}
測試結果
此時在MyChild1中定義了一個str2,並在main方法中調用的str2,是對MyChild類的一次主動使用,自然會初始化,自然也就會執行靜態代碼塊,輸出語句
而對於爲什麼MyParent1也會輸出語句?
是因爲主動使用裏有一條
出初始化一個類的子類,那麼也就是這個父類也會被主動使用,進行一次初始化。
父類會進行先行初始化
測試總結:
對於一個靜態字段來說,只有直接定義了該字段的類纔會被初始化
當一個類在初始化時,要求其父類全部都已經初始化完畢
這就是問什麼輸出語句有先後順序