public class T {
public static int k = 0;
public static T t1 = new T("t1");
public static T t2 = new T("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造快");
}
static {
print("静态块");
}
public T(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
T t = new T("init");
}
}
可能出现在class文件中的两种编译器产生的方法是:
- 实例初始化方法(名为<init>
):负责初始化实例变量与执行该类的构造方法
- 类与接口初始化方法(名为<clinit>
):负责初始化类变量与执行静态代码块。
两者的区别见:http://blog.csdn.net/x_iya/article/details/77097118
对于如上的代码,其对应的等价代码如下:
public class T {
public static int k;
public static T t1;
public static T t2;
public static int i;
public static int n;
static {
k = 0;
t1 = new T("t1");
t2 = new T("t2");
i = print("i");
n = 99;
print("静态块");
}
public int j;
public T(String str) {
j = print("j");
print("构造快");
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
T t = new T("init");
}
}
static代码块即为虚拟机中生成的<clinit>
方法,构造函数即为虚拟机中生成的<init>
方法
以上代码的反汇编结果为:
D:\N3verL4nd\Desktop>javap -c T
Compiled from "T.java"
public class T {
public static int k;
public static T t1;
public static T t2;
public static int i;
public static int n;
public int j;
public T(java.lang.String);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String j
7: invokestatic #3 // Method print:(Ljava/lang/String;)I
10: putfield #4 // Field j:I
13: ldc #5 // String 构造快
15: invokestatic #3 // Method print:(Ljava/lang/String;)I
18: pop
19: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
22: new #7 // class java/lang/StringBuilder
25: dup
26: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
29: getstatic #9 // Field k:I
32: iconst_1
33: iadd
34: dup
35: putstatic #9 // Field k:I
38: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
41: ldc #11 // String :
43: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
46: aload_1
47: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
50: ldc #13 // String i=
52: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
55: getstatic #14 // Field i:I
58: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
61: ldc #15 // String n=
63: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
66: getstatic #16 // Field n:I
69: invokevirtual #10 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
72: invokevirtual #17 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
75: invokevirtual #18 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
78: getstatic #16 // Field n:I
81: iconst_1
82: iadd
83: putstatic #16 // Field n:I
86: getstatic #14 // Field i:I
89: iconst_1
90: iadd
91: putstatic #14 // Field i:I
94: return
static {};
Code:
0: iconst_0
1: putstatic #9 // Field k:I
4: new #19 // class T
7: dup
8: ldc #22 // String t1
10: invokespecial #21 // Method "<init>":(Ljava/lang/String;)V
13: putstatic #23 // Field t1:LT;
16: new #19 // class T
19: dup
20: ldc #24 // String t2
22: invokespecial #21 // Method "<init>":(Ljava/lang/String;)V
25: putstatic #25 // Field t2:LT;
28: ldc #26 // String i
30: invokestatic #3 // Method print:(Ljava/lang/String;)I
33: putstatic #14 // Field i:I
36: bipush 99
38: putstatic #16 // Field n:I
41: ldc #27 // String 静态块
43: invokestatic #3 // Method print:(Ljava/lang/String;)I
46: pop
47: return
}
加载过程分析:
1、执行main方法(T.main),导致 T 类的加载。
2、在类的准备阶段(加载、验证、准备、解析、初始化)会为静态变量分配存储空间并且赋初始值。对于上述代码中声明的静态变量k、t1、t2、i、n被初始化为(0,null,null,0,0)
3、在初始化阶段为类变量赋值(用户自定义的值),也就是执行上述等价的static方法。k被第二次赋值,k=0。t1 = new T(“t1”);在对t1进行初始化的过程中触发了<init>
方法的执行。此时不会再去执行<clinit>
方法了。t2也是一样的操作。注意此时对于类变量i与n还都没有进行用户自定义初始化,还都是0。
4、执行i = print(“i”);n = 99;print(“静态块”);
5、以上就完成了<clinit>
的执行,由JVM调用。然后再去执行<init>
方法。
所以输出结果为:
1:j i=0 n=0
2:构造快 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造快 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造快 i=9 n=101
11:init i=10 n=102