学习是最好的投资!
類別變數(靜態變數)>靜態區塊>建構方法>普通成員變數>子類別除靜態外。 JAVA所有static修飾的都會在編譯時分配空間,而物件只會在使用時才分配即new的時候,子類別繼承父類別很明顯需要先給父類別分配,沒有父親哪來的兒子是吧
題主可以透過編譯後的class檔反編譯來幫助理解初始化過程。
class
在命令列中的指令javap -l -c -p -v App,执行后就会得到反编译后的内容,下面结合题主给的源码简单分析一下:下面展示和初始化有关的部分反编译内容App的class檔案
javap -l -c -p -v App
App
private static com.real.test.App d; descriptor: Lcom/real/test/App; flags: ACC_PRIVATE, ACC_STATIC private com.real.test.SubClass t; descriptor: Lcom/real/test/SubClass; flags: ACC_PRIVATE static {}; descriptor: ()V flags: ACC_STATIC Code: stack=2, locals=0, args_size=0 0: new #1 // class com/real/test/App 3: dup 4: invokespecial #12 // Method "<init>":()V **调用App的构造函数** 7: putstatic #15 // Field d:Lcom/real/test/App; 10: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream; 13: iconst_3 **得到数字常量3** 14: invokevirtual #23 // Method java/io/PrintStream.println:(I)V **打印数字常量3** 17: return LineNumberTable: line 4: 0 line 8: 10 line 3: 17 LocalVariableTable: Start Length Slot Name Signature com.real.test.App(); **构造函数详细内容** descriptor: ()V flags: Code: stack=3, locals=1, args_size=1 0: aload_0 1: invokespecial #31 // Method java/lang/Object."<init>":()V **调用Object的构造函数** 4: aload_0 5: new #32 // class com/real/test/SubClass 8: dup 9: invokespecial #34 // Method com/real/test/SubClass."<init>":()V **调用SubClass的构造函数** 12: putfield #35 // Field t:Lcom/real/test/SubClass; 15: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream; 18: iconst_4 **得到数字常量4** 19: invokevirtual #23 // Method java/io/PrintStream.println:(I)V **打印数字常量4** 22: return LineNumberTable: line 11: 0 line 5: 4 line 12: 15 line 13: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 this Lcom/real/test/App; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #40 // String Hello **得到字符串Hello** 5: invokevirtual #42 // Method java/io/PrintStream.println:(Ljava/lang/String **打印字符串** 8: return LineNumberTable: line 16: 0 line 17: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 args [Ljava/lang/String;
SubClass的class檔案
SubClass
static {}; **静态块** descriptor: ()V flags: ACC_STATIC Code: stack=2, locals=0, args_size=0 0: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 3: iconst_1 **得到数字常量1** 4: invokevirtual #14 // Method java/io/PrintStream.println:(I)V **打印数字常量1** 7: return LineNumberTable: line 28: 0 line 26: 7 LocalVariableTable: Start Length Slot Name Signature public com.real.test.SubClass(); **构造函数** descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #23 // Method com/real/test/SuperClass."<init>":()V **调用SuperClass的构造函数** 4: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 7: iconst_2 **得到数字常量2** 8: invokevirtual #14 // Method java/io/PrintStream.println:(I)V **打印数字常量2** 11: return LineNumberTable: line 31: 0 line 32: 4 line 33: 11 LocalVariableTable: Start Length Slot Name Signature 0 12 0 this Lcom/real/test/SubClass;
SuperClass的class檔案
SuperClass
com.real.test.SuperClass(); descriptor: ()V flags: Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V **Object的构造函数** 4: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream; 7: ldc #16 // String 构造SuperClass **得到字符串构造SuperClass** 9: invokevirtual #18 // Method java/io/PrintStream.println:(Ljava/lang/String;)V **打印字符串** 12: return LineNumberTable: line 21: 0 line 22: 4 line 23: 12 LocalVariableTable: Start Length Slot Name Signature 0 13 0 this Lcom/real/test/SuperClass;
大致解釋一下內容(如果題主對JVM指令集有興趣看看JVM規範,裡面有很詳細的解釋)。 上面反編譯內容中星號部分是我加上的註解。依照程式碼的執行順序:1.JVM載入App類,App中的靜態變數在這時會初始化,對應App中呼叫App的建構函數的字節碼2.跳到App的建構函數,先初始化父類別Object,對應App中呼叫Object的建構子3.初始化實例變數JVM指令集感兴趣可以看看JVM规范,里面有很详细的解释)。上面反编译内容中星号部分是我加上的注解。按照代码的执行顺序:1.JVM加载App类,App中的静态变量在这时会初始化,对应App中调用App的构造函数的字节码2.跳到App的构造函数,先初始化父类Object,对应App中调用Object的构造函数3.初始化实例变量SubClass,对应App中调用SubClass的构造函数4.此时要先加载SubClass类,同时初始化静态变量并执行静态块,对应SubClass中静态块5.这时执行SubClass中的代码打印出“1”6.SubClass加载完成后执行构造函数,对应SubClass中构造函数7.SubClass构造函数最开始是执行SuperClass的构造函数,对应SubClass中调用SuperClass的构造函数8.执行SuperClass中构造函数中的代码打印出“得到字符串构造SuperClass”9.SuperClass构造完成return到7中的代码位置,继续执行SubClass剩余的代码10.执行SubClass中构造函数代码打印出“2”11.执行完SubClass构造函数return到3中的代码位置,继续执行App剩余的代码12.执行App中构造函数代码打印出“4”13.执行完App的构造函数return到1中代码位置,继续初始化的静态变量14.执行静态块中的方法,答应出“3”15.进入到main,對應App中呼叫SubClass的建構子4.此時要先載入
JVM指令集
JVM
呼叫App的建構函數
Object
呼叫Object的建構子
调用App的构造函数
调用Object的构造函数
调用SubClass的构造函数
静态块
构造函数
调用SuperClass的构造函数
return
main
呼叫SubClass的建構子
靜態區塊
中的程式碼列印出「1」6.
建構子最開始是執行
呼叫SuperClass的建構子
類別變數(靜態變數)>靜態區塊>建構方法>普通成員變數>子類別除靜態外。 JAVA所有static修飾的都會在編譯時分配空間,而物件只會在使用時才分配即new的時候,子類別繼承父類別很明顯需要先給父類別分配,沒有父親哪來的兒子是吧
題主可以透過編譯後的
class
檔反編譯來幫助理解初始化過程。在命令列中的指令
javap -l -c -p -v App
,执行后就会得到反编译后的内容,下面结合题主给的源码简单分析一下:下面展示和初始化有关的部分反编译内容
App
的class檔案SubClass
的class檔案SuperClass
的class檔案大致解釋一下內容(如果題主對
類,同時初始化靜態變數並執行靜態區塊,對應SubClass中JVM指令集
有興趣看看JVM
規範,裡面有很詳細的解釋)。上面反編譯內容中星號部分是我加上的註解。依照程式碼的執行順序:
1.JVM載入
App
類,App
中的靜態變數在這時會初始化,對應App中呼叫App的建構函數
的字節碼2.跳到
App
的建構函數,先初始化父類別Object
,對應App中呼叫Object的建構子
3.初始化實例變數
JVM指令集
感兴趣可以看看JVM
规范,里面有很详细的解释)。上面反编译内容中星号部分是我加上的注解。按照代码的执行顺序:
1.JVM加载
App
类,App
中的静态变量在这时会初始化,对应App中调用App的构造函数
的字节码2.跳到
App
的构造函数,先初始化父类Object
,对应App中调用Object的构造函数
3.初始化实例变量
SubClass
,对应App中调用SubClass的构造函数
4.此时要先加载
SubClass
类,同时初始化静态变量并执行静态块,对应SubClass中静态块
5.这时执行
SubClass
中的代码打印出“1”6.
SubClass
加载完成后执行构造函数,对应SubClass中构造函数
7.
SubClass
构造函数最开始是执行SuperClass
的构造函数,对应SubClass中调用SuperClass的构造函数
8.执行
SuperClass
中构造函数中的代码打印出“得到字符串构造SuperClass”9.
SuperClass
构造完成return
到7中的代码位置,继续执行SubClass
剩余的代码10.执行
SubClass
中构造函数代码打印出“2”11.执行完
SubClass
构造函数return
到3中的代码位置,继续执行App
剩余的代码12.执行
App
中构造函数代码打印出“4”13.执行完
App
的构造函数return
到1中代码位置,继续初始化的静态变量14.执行静态块中的方法,答应出“3”
15.进入到
main
,對應App中呼叫SubClass的建構子
4.此時要先載入
靜態區塊
5.這時執行
中的程式碼列印出「1」
載入完成後執行建構函數,對應SubClass中建構子6.
7.
建構子最開始是執行
的建構函數,對應SubClass中呼叫SuperClass的建構子
8.執行🎜中建構函數中的程式碼印出「得到字串構造SuperClass」
9.🎜構造完成
return
到7中的程式碼位置,繼續執行🎜剩餘的程式碼10.執行🎜中構造函式碼印出「2」
11.執行完🎜建構子
return
到3中的程式碼位置,繼續執行App
剩餘的程式碼12.執行
App
中建構函式碼印出「4」13.執行完
App
的建構子return
到1中程式碼位置,繼續初始化的靜態變數14.執行靜態區塊中的方法,答應出「3」
15.進入到
main
入口方法,列印出「Hello」🎜 🎜上面的過程就是大致的執行順序。 🎜 🎜回答的內容可能會有點混亂,題主看不懂的地方可以問我。 🎜