1、代码块,静态代码块,构造方法执行顺序
结论:
1、优先级:静态代码块 > 代码块 > 构造方法
2、静态代码块 在首次类进行初始化的时候进行调用
3、代码块 每次创建对象时,都会执行,且在构造方法之前
4、构造方法 每次创建对象都会执行
1 | package com.wangqd.jvm.test; |
2、存在继承关系时,代码块,静态代码块,构造方法执行顺序
结论:
1、当一个类在初始化时,要求其父类全部都已经初始化完毕
2、优先级:静态代码块 > 代码块 > 构造方法
3、创建子类对象时会先加载父类,静态代码块会优先被加载
4、创建对象时 代码块和构造方法会一起被加载,存在父类则先加载父类的代码块和构造方法
1 | package com.wangqd.jvm.test; |
3、static final变量的加载
- static final 修饰常量
结论:引用被static final 修饰的常量( 包含原生数据类型和字符串)时,确定的值则不会初始化常量的类
1 | package com.wangqd.jvm.test; |
获取class文件的字节码:javap -c com.wangqd.jvm.test.Test4
可以看到Test4的字节码文件中存在 hello world,说明static final 的常量编译后直接存储在Test4中,所以Test4调用MyTest4.hello,会直接将其替换为常量。1
2
3
4
5
6
7
8
9
10
11
12
13
14public class com.wangqd.jvm.test.Test4 {
public com.wangqd.jvm.test.Test4();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String hello world
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
也可以通过反编译工具编译Test4 发现MyTest4.hello直接被替换为hello
- static final 修饰变量
结论:引用被static final 修饰的变量(对象)时,会初始化变量的类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
26
27
28
29
30
31package com.wangqd.jvm.test;
import java.util.Random;
public class Test4 {
public static void main(String[] args) {
System.out.println(MyTest4.random);
}
}
class MyTest4 {
public static final Random random = new Random();
static {
System.out.println("MyTest4 static block invoked");
}
{
System.out.println("MyTest4 block invoked");
}
public MyTest4() {
System.out.println("MyTest4 constructor invoked");
}
}
/*
out:
MyTest4 static block invoked
java.util.Random@2b05039f
*/
获取class文件的字节码:javap -c com.wangqd.jvm.test.Test4
发现Random对应的是getstatic(访问某个类或者接口的静态变量)1
2
3
4
5
6
7
8
9
10
11
12
13
14public class com.wangqd.jvm.test.Test4 {
public com.wangqd.jvm.test.Test4();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3 // Field com/wangqd/jvm/test/MyTest4.random:Ljava/util/Random;
6: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
9: return
}
4、 static 变量的加载
结论:引用类的static成员变量会初始化,改static成员变量的类
1 | package com.wangqd.jvm.test; |
5、 存在继承关系时,static 变量的加载
当调用子类的static成员变量时
首先,加载static成员变量会加载成员变量所在的类,当一个类在初始化时,要求其父类全部都已经初始化完,所以会先加载父类,然后在初始化自己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
26
27
28
29
30
31
32
33
34
35package com.wangqd.jvm.test;
public class Test6 {
public static void main(String[] args) {
System.out.println(MyChild6.str2);
}
}
class MyParent6{
public static String str = "hello world";
static {
System.out.println("MyParent1 static block");
}
{
System.out.println("MyParent1 block");
}
}
class MyChild6 extends MyParent6{
public static String str2 = "welcome";
static {
System.out.println("MyChild1 static block");
}
{
System.out.println("MyChild block");
}
}
/*
out:
MyParent1 static block
MyChild1 static block
welcome
*/当调用子类从父类继承的static成员变量时
只会初始化父类,不会初始化自己。即只有直接定义了该字段的类才会被初始化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
26
27
28
29
30
31
32
33
34
35package com.wangqd.jvm.test;
public class Test6 {
public static void main(String[] args) {
System.out.println(MyChild6.str);
}
}
class MyParent6{
public static String str = "hello world";
static {
System.out.println("MyParent1 static block");
}
{
System.out.println("MyParent1 block");
}
}
class MyChild6 extends MyParent6{
public static String str2 = "welcome";
static {
System.out.println("MyChild1 static block");
}
{
System.out.println("MyChild block");
}
}
/*
out:
MyParent1 static block
hello world
*/