本文章用於對類加載實例代碼的詳解部分
前情回顧
所有的Java虛擬機必須在每個類或者接口被Java程序“首次主動使用時”才初始化它們,如果不是首次使用或非主動使用是不會被初始化的。
主動使用分爲:
- 創建類的實例
- 訪問某個類或某個接口的靜態變量(助記符爲getstatic),或者對它們的靜態變量進行賦值(助記符爲putstatic)
- 調用類的靜態方法(助記符爲invokestatic)
- 反射(如Class.forName(“com.test.Test”)
- 初始化一個類的子類
- Java虛擬機啓動時被標明啓動類的類,虛擬機啓動時,用戶需要指定一個要執行的主類(包含 main() 方法的那個類),虛擬機會先初始化這個主類。
- 動態語言…
public class MyTest1 {
public static void main(String[] args) {
System.out.println(MyChild1.str);//輸出Myparent1 static block Hello World
}
}
class Myparent1{
public static String str="Hello World";
static {
System.out.println("Myparent1 static block");
}
}
class MyChild1 extends Myparent1{
public static String str2="Hello World2";
static {
System.out.println("MyChild1 static block");
}
}
解析 :在main中我們通過子類訪問了父類的靜態代碼,會輸出什麼?
輸出是 :Myparent1 static block Hello World
補充知識(靜態代碼塊是在初始化的時候被執行的)
也就是先輸出父類代碼塊中的靜態代碼塊再輸出靜態字段,而子類的靜態代碼塊並沒有輸出,
這說明了什麼?說明了父類被初始化了而子類沒有 通過子類訪問父類的靜態變量只會導致父類的初始化而不會導致子類的初始化
而如果直接訪問子類的靜態代碼會輸出什麼呢?
即:
public class MyTest1 {
public static void main(String[] args) {
System.out.println(MyChild1.str2);//輸出Myparent1 static block MyChild1 static block Hello World2
}
}
class Myparent1{
public static String str="Hello World";
static {
System.out.println("Myparent1 static block");
}
}
class MyChild1 extends Myparent1{
public static String str2="Hello World2";
static {
System.out.println("MyChild1 static block");
}
}
其輸出是:Myparent1 static block MyChild1 static block Hello World2
很明顯,**調用子類的靜態字段會導致父類和子類都初始化,也就是看做對父類的主動使用。
那麼,當我們通過子類調用父類的靜態字段時,子類有沒有被加載呢?(不明白加載的同學看這裏)
我們通過設置虛擬機參數:-XX:+TraceClassLoading
這個參數表示在控制檯輸出虛擬機加載的類信息
[Loaded classloader.MyTest1 from file:/C:/Users/%e9%a5%b6%e7%8f%82/Desktop/jvm-learning/target/classes/]
[Loaded classloader.Myparent1 from file:/C:/Users/%e9%a5%b6%e7%8f%82/Desktop/jvm-learning/target/classes/]
[Loaded classloader.MyChild1 from file:/C:/Users/%e9%a5%b6%e7%8f%82/Desktop/jvm-learning/target/classes/]
Myparent1 static block
Hello World
以上是控制檯輸出的一部分,其中省去了大量片段只保留了重要的,第一行即類加載器首先加載了MyTest1,即主類,即main方法所在的類,然後加載了MyParent1,再加載了MyChild1,再進行輸出
我們可以看到類加載器先加載主類,然後根據代碼內容進行加載有繼承關係的父類,然後才加載子類。
補充知識:
-
jvm參數
-XX:+<option>
開啓option選項 即-XX:+TraceClassLoading
,開啓TraceClassLoading
選項-XX:-<option>
關閉option選項-XX:<option>=<value>
將option選項設置爲value
https://www.cnblogs.com/czwbig/p/11127222.html