1.没有继承情况下的初始化顺序
1 package InitializationOrder;
2 /**
3 * 没有继承的初始化顺序
4 * @author TANJIAYI
5 *
6 */
7 public class Test4 {
8 public static void main(String[] args) {
9 new Order();
10 }
11 }
12 class Order{
13 AAA s = new AAA("成员变量");
14 static AAA a = new AAA("静态成员变量");
15 {
16 System.out.println("初始化块");
17 }
18 static{
19 System.out.println("静态初始化块");
20 }
21 Order(){
22 System.out.println("构造方法");
23 }
24
25 }
26 class AAA{
27 public AAA(String str){
28 System.out.println(str);
29 }
30 }
输出结果:
静态成员变量
静态初始化块
成员变量
初始化块
构造方法
结论:在没有继承的条件下,实例化一个对象,构造的先后顺序是,静态成员变量>静态初始化块>成员变量>初始化块>构造方法
一般顺序为 先静态,后非静态,先变量,后初始化块,再是构造方法
2.经典面试题
直接上代码:
1 package InitializationOrder;
2 /**
3 * 初始化顺序 静态变量 静态初始化块 成员变量 初始化块 构造函数
4 * @author TANJIAYI
5 *
6 */
7 public class Test1 {
8
9 public static Test1 t1 = new Test1("t1");//第1步
10 public static int k = 0;
11 public static Test1 t2 = new Test1("t2");//第2步
12 public static int i = print("i");//第3步
13 public static int n = 99;//第4步
14 public int j = print("j");//第6步
15 {
16 print("构造");//第7步
17 }
18 static{
19 print("静态");//第5步
20 }
21 public Test1(String str){
22 System.out.println((++k)+":"+str+" i="+i+" n="+n);
23 ++i;
24 ++n;
25 }
26 private static int print(String str) {
27 System.out.println((++k)+":"+str+" i="+i+" n="+n);//1:j i=0 n=0
28 ++n;
29 return ++i;
30 }
31 public static void main(String[] args) {
32 Test1 test = new Test1("init");//第8步
33 }
34 }
输出结果为:
1:j i=0 n=0
2:构造 i=1 n=1
3:t1 i=2 n=2
1:j i=3 n=3
2:构造 i=4 n=4
3:t2 i=5 n=5
4:i i=6 n=6
5:静态 i=7 n=99
6:j i=8 n=100
7:构造 i=9 n=101
8:init i=10 n=102
解题思路:
(1) 按照对象初始化顺序依次执行,首先静态变量从代码中的第九行到第13行依次执行。
(2) 执行第1步,调用new Test1()方法,本方法是个构造方法,在执行前,类加载的时候先把k,i和n的值加载进来,初始值为0,接着执行第14行成员变量j;调用print()方法,把j赋给str,所以27行代码打印第一条输出:1:j i=0 n=0,在执行初始化块,15—17行,打印出2:构造 i=1 n=1,最后在执行Test1()构造方法,打印出 3:t1 i=2 n=2,第1步语句执行完毕,接着执行第2步。
(3) 分析同上,逐步打印出答案。
为了好理解,下面附上一张图,挨着挨着看思路还是很清楚的哦!图画得有点儿乱:
总结:大家只要掌握好执行的先后顺序,仔细分析题,就没有问题。
2.继承情况下对象的初始化顺序
属性、方法、构造方法和自由块都是类中的成员,在创建类的对象时,类中各成员的执行顺序:
1.父类静态成员和静态初始化快,按在代码中出现的顺序依次执行。
2.子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
3. 父类的实例成员和实例初始化块,按在代码中出现的顺序依次执行。
4. 执行父类的构造方法。
5.子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
6.执行子类的构造方法。
1 package InitializationOrder; 2 /** 3 * 继承下的初始化顺序 4 * @author TANJIAYI 5 * 6 */ 7 public class Test2 { 8 public static void main(String[] args) { 9 new Son(); 10 } 11 } 12 class Parent{ 13 14 { 15 System.out.println("parent中的初始化块"); 16 } 17 static{ 18 System.out.println("parent中static初始化块"); 19 } 20 21 public Parent(){ 22 System.out.println("parent构造方法"); 23 } 24 } 25 26 class Son extends Parent{ 27 { 28 System.out.println("son中的初始化块"); 29 } 30 31 static{ 32 System.out.println("son中的static初始化块"); 33 } 34 35 public Son(){ 36 System.out.println("son构造方法"); 37 } 38 }
输出结果:
- 初始化块主要用于对象的初始化操作,在创建对象时调用,可以用于完成初始化属性值、加载其他的类的功能。
- 初始化块和构造方法功能类似,可以再创建对象的时候完成一些初始化的操作,一般的情况下,构造方法初始化和初始化块初始化可以通用。
- 构造方法在初始化的时候可以通过参数传递,但是初始化块不能,初始化块的初始化在构造方法之前执行,如果搞糟方法多次重载,此时可以考虑构造方法中共通的代码放到初始化块中进行初始化。
补充:
静态初始化块和非静态初始化块的区别?
- 非静态初始化块主要是用于对象的初始化操作,在每次创建对象的时都要调用一次,其执行顺序在构造方法之前。
- 在初始化块之前有static修饰,则为静态初始化块。由于非静态成员不能再静态方法中使用,同样也不能在静态初始化块中,因此,静态初始化块主要用于初始化静态变量和静态方法,静态初始化块只调用一次,是在类的第一次加载到内存时,并非一定要创建对象才执行。
- 静态初始化块比非静态初始化块先执行
知了堂:www.zhiliaotang.com
写得比较随意,很多地方,很不完全,希望广大的友友们,发现问题,给我留言,指正。