高洛峰2017-04-18 10:38:29
Class variables (static variables) > Static blocks > Constructors > Ordinary member variables > Subclasses except static. All static modifications in JAVA will allocate space at compile time, and objects will only be allocated when used, that is, when new is used, when a subclass inherits a parent class, it obviously needs to be allocated to the parent class first. How can a son come from without a father, right?
迷茫2017-04-18 10:38:29
The subject can help understand the initialization process by decompiling the compiled class
file.
Instructions in the command linejavap -l -c -p -v App
,执行后就会得到反编译后的内容,下面结合题主给的源码简单分析一下:
下面展示和初始化有关的部分反编译内容App
class file
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 file
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 file
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;
Explain the content roughly (if the subject is interested in JVM instruction set
, you can read the JVM
specification, which has a very detailed explanation).
The asterisked part in the decompiled content above is the annotation I added. According to the execution order of the code:
1. JVM loads the App
class. The static variables in App
will be initialized at this time, corresponding to the calling App in the App. Bytecode of constructor
2. Jump to the constructor of App
, first initialize the parent class Object
, and call Object corresponding to in App Constructor of
3. Initialize the instance variable 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
, which corresponds to calling the constructor of SubClass in the App
4. At this time, the
static block
prints out "1"
6. After
constructor is initially the constructor that executes
, corresponding to theconstructor that calls SuperClass in SubClass
return
to the code position in 7, and continue to execute the remaining codereturn
to the code position in 3, continue executing the remaining code of App
App
to print out "4"App
, return
to the code position in 1, Continue to initialize the static variablesmain
entry method and print out "Hello"🎜
🎜The above process is the rough execution sequence. 🎜
🎜The content of the answer may be a bit confusing. If you don’t understand something, you can ask me. 🎜