众所周知,java程序入口为main方法,但java程序首先执行的并不一定是main程序的第一句话。
1 2 3 4 5 6 7 8 9 10 11 public class Test { static{ System.out.println("构造块"); } public static void main(String[] args) { System.out.println("main start"); Test t = new Test(); } }
在上面这个例子中,可以看到构造块先于main start输出。这是因为静态部分是属于类,而不是属于对象的,jvm首先加载类,而后在运行过程中有需要再进行类的实例化。
在一般情况下,代码执行顺序如下:
父类的静态属性 静态方法声明 静态块
静态属性 静态方法声明 静态块
父类的动态属性 普通方法声明 构造块
父类构造方法
动态属性 普通方法声明 构造块
构造方法
当加载一个类时,jvm首先为静态属性一并赋予默认值,按静态相关代码出现顺序执行(静态属性初始化,静态方法的声明,静态块的加载),且静态代码仅执行一次(仅加载一次,双亲委托避免重复加载类)。
当新建一个对象时,会调用该对象的构造方法。但在这之前,会先为动态属性一并赋予默认值(此时类加载已完成,除非因静态代码中实例化被打断而暂停),然后按代码出现顺序执行(动态属性初始化,构造块,方法声明)。最后执行构造方法。
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 35 36 37 38 39 40 41 42 43 public class Test { public static int i = 0 ; private static int j = print(); public static int print () { System.out.println("print i:" + i); return ++i; } static { System.out.println("Test的构造块" ); } public Test () { System.out.println("Test的构造方法 i:" + print()); } } public class TestParent extends Test { static int p = print(); public static int j = 10 ; public static int print () { System.out.println("print j:" + j); return ++j; } static { System.out.println("TestParent的构造块" ); } public TestParent () { System.out.println("TestParent的构造方法 j:" + print()); } public static void main (String[] args) { System.out.println("main start" ); TestParent t = new TestParent(); } }
执行结果如下:
1 2 3 4 5 6 7 8 9 print i:0 Test的构造块 print j:0 TestParent的构造块 main start print i:1 Test的构造方法 i:2 print j:10 TestParent的构造方法 j:11
在类加载过程中,如果静态部分有实例对象操作,则会暂停类加载而进行类实例化,来看下面这一段代码:
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 public class Text { public static int k = 0 ; public static Text t1 = new Text("t1" ); public static Text t2 = new Text("t2" ); public static int i = print("i" ); public static int n = 99 ; public int j = print("j" ); { print("构造块" ); } static { print("静态块" ); } public Text (String str) { System.out.println((++k) + ":" + str + " i=" + i + " n=" + n); ++i; ++n; } public static int print (String str) { System.out.println((++k) + ":" + str + " i=" + i + " n=" + n); ++n; return ++i; } public static void main (String args[]) { Text t = new Text("init" ); } }
执行结果如下:
1 2 3 4 5 6 7 8 9 10 11 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
在这里先进行了public int j = print(“j”); 的执行,是因为在类加载时遇到了public static Text t1 = new Text(“t1”); 实例化操作,所以就出现了以上执行结果。