<clinit>()方法
Java 類加載的初始化過程中,編譯器按語句在源文件中出現的順序,依次自動收集類中的所有類變量的賦值動作和靜態代碼塊中的語句合并產生方法。 如果類中沒有靜態語句和靜態代碼塊,那可以不生成<clinit>() 方法。
并且 <clinit>() 不需要顯式調用父類(接口除外,接口不需要調用父接口的初始化方法,只有使用到父接口中的靜態變量時才需要調用)的初始化方法 <clinit>(),虛擬機會保證在子類的 <clinit>() 方法執行之前,父類的 <clinit>() 方法已經執行完畢(所以java.lang.Object 類總是第一個被加載)
準備父類和子類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class Father { static int father_a = 1 ; static { System.out.println( "父類靜態代碼塊執行" ); } static class StaticInnerClass { static { System.out.println( "靜態內部類靜態代碼塊執行" ); } } } class Son extends Father { static { System.out.println( "子類靜態代碼塊執行" ); son_a = 300 ; } static int son_a = 100 ; static final int M = 1 ; } |
Main方法:
1:父類沒有被引用但是會被先加載
new Son();
2:反射也會產生主動引用:
Class a = Class.forName("clinit.Son");
(運行結果同1)
3:子類使用父類靜態變量或方法不會產生類的引用
System.out.println("Father.a = " + Son.father_a);
4:通過類創建數組不會加載類(只是開辟一塊空間)
Son[] sons = new Son[8];
5:使用常量不會加載父類和之類(常量在Linking階段就保存在常量池當中了)
System.out.println("Son.CONST = " + Son.CONST);
6:引用靜態內部類不會加載外部類(應用于單例模式)
new Father.StaticInnerClass();
代碼總結:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public static void main(String[] args) throws Exception { // 1.父類沒有被引用但是會被先加載 // new Son(); // 2.反射會產生主動引用 // Class a = Class.forName("clinit.Son"); // 3.子類使用父類靜態變量或方法不會產生類的引用 // System.out.println("Father.a = " + Son.father_a); // 4.通過類創建數組不會加載類(只是開辟一塊空間) // Son[] sons = new Son[8]; // 5.使用常量不會加載父類和之類(常量在Linking階段就保存在常量池當中了) // System.out.println("Son.CONST = " + Son.CONST); // 6.引用靜態內部類不會加載外部類(應用于單例模式) // new Son.StaticInnerClass(); } } |
PS:由于是按出現的順序執行的,為了避免不必要的麻煩,應盡量把靜態變量寫在靜態代碼塊之前
1
2
3
4
5
6
7
|
public class Test { public static void main(String[] args) { System.out.println( "a = " + cls.a); } } class cls { static int a = 10 ; 8 static { a = 20 ; } 9 } |
如果 調換順序輸出結果將是 a = 10
1
2
3
4
|
class cls { static { a = 20 ; } static int a = 10 ; } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://www.cnblogs.com/whyha/p/13420219.html