Java对象的建构顺序

对于下面的代码,许多有经验的程序员都没能给出正确的答案。如果你能只看代码给出的答案和文章末尾出给出大答案一致,那么你已经掌握了Java对象的建构顺序,中间的分析可以不用看了。

1 /**  
2 * 父类Foo,实现控制台输出  
3 *  
4 * @author youngto  
5 * @since 2013-01-25  
6 */  
7 class Foo {  
8  
9 private int index = 100;  
10  
11 //静态代码块  
12 static {  
13 System.out.println("Foo static");  
14 }  
15  
16 //初始化代码块  
17 {  
18 System.out.println("Foo initialization");  
19 }  
20  
21 public Foo() {  
22 System.out.println("Foo constructor");  
23 System.out.println(printIndex());  
24 }  
25  
26 protected int printIndex() {  
27 return index;  
28 }  
29  
30 }  
31  
32 /**  
33 * 子类Bar,实现控制台输出  
34 *  
35 * @author youngto  
36 * @since 2013-01-25  
37 */  
38 public class Bar extends Foo{  
39  
40 private int index = 100;  
41 static Bar bar = new Bar();  
42  
43 //静态代码块  
44 static{  
45 System.out.println("Bar static");  
46 }  
47  
48 //初始化代码块  
49 {  
50 System.out.println("Bar initialization");  
51 }  
52  
53 public Bar() {  
54 System.out.println("Bar constructor");  
55 System.out.println(printIndex());  
56 }  
57  
58 @Override  
59 protected int printIndex() {  
60 System.out.println(bar);  
61 return index;  
62 }  
63  
64 public static void main(String[] args) {  
65 Foo foo = new Bar();  
66 System.out.println(foo.printIndex());  
67 foo = new Bar();  
68 }  
69  
70 }

 

 在对象建构过程中。为确保其正确性,以下事件一定会以固定顺序发生:

a、从heap之中分配内存,用以存放全部的 instance 变量以及这个对象连同其 superclasses的实现专属数据(implementation-specific data)。所谓「实现专属数据」包括指向“class and method data的指针。

b、 对象的Instance变量被初始化为其相应的缺省值。

c、调用most derived class(最深层派生类)的构造函数(constructor)(注:事实上,构造函数被.class文件中的一个initialization method(初始化函数)替换了。Initialization method是名为<init>的特殊函数,由Java编译器安放在.class文件里。其中包含[构造函数代码]、[instance变量之初始化代码],以及[调用superclass Initialization method]之代码。)。构造函致做的第一件事就是调用superclass的构造函数。这个程序一直反复持续到 java.lang.object构适函数被调用为止。一定要记住,java.lang.object是一切java对象的base class。

d、所有对象的静态代码块或静态字段先获得执行,优先级从父类开始。

e、在构造函数本体执行之前,所有 instance 变量的初值设定式(initializers)和初始化区(initialization blocks)先获得执行,然后才执行构造函数本体。于是base class的构造函数最先执行,most derived class的构造函数最后执行。这使得任何class的构造函数都能放心大胆地使用其任何superclass 的instance 变量。

代码分析:

1、根据a:从heap分配内存,用来存放Bar的instance变量(index和bar)、Foo的instance变量(index),和一份「实现专属数据」。

2、根据b:instance变量被初始化为其相应缺省值,Bar的index被赋值为0,bar被赋值为null,Foo的index被赋值为0。

3、根据c:在代码65行准备创建Bar的一个对象,调用Bar的构造函数立即调用其superclass Foo的构造函数,Foo构造函数立即调用其superclass java.lang.Object的构造函数。

4、根据d:java.lang.Object构造函数返回后,在Foo对象中执行静态代码块输出Foo static,Foo静态代码块执行完,执行Bar静态代码此时代码执行到41行,准备创建Bar的第二个对象,针对这个对象,又从步骤1开始重复全部过程。

5、将要创建第二个Bar对象代码再次执行到Foo对象,由于静态对象只初始化一次,所以不会再次执行Foo的静态代码块,直接先执行初始化代码块输出Foo initialization,再执行Foo构造函数本体,根据e:Foo的index被赋值为100(这是来迷惑你的),输出Foo constructor;在Foo的构造函数中调用了printIndex函数,由于printIndex函数已经被子类Bar重写所以此时调用的是Bar中的printIndex函数,根据e:此时代码还未执行到Bar的构造函数本体,所以此时printIndex函数输出缺省值bar=null,返回Bar的index缺省值0,因此这一步输出null,0,Foo构造函数完成,返回。

6、继续构建第二个Bar对象,执行Bar的初始化代码块,输出Bar initialization,再执行构造函数,输出Bar constructor。此时Bar的index赋值100,Bar的bar对象还正在构建中所以为null,输出null,100,Bar构造函数完成。

7、Object reference bar指向heap之中最后创建完成的Bar对象,此时在第一个Bar的对象创建过程中而创建的第二Bar对象创建完成。

8、继续第一个Bar对象的创建、执行Bar的静态代码块,输出Bar static。

9、从4-8步静态代码执行完成,继续执行Foo的初始化代码块输出Foo initialization,再执行Foo的构造函数本体输出Foo constructor。在Foo的构造函数中调用了printIndex函数,由于printIndex函数已经被子类Bar重写所以此时调用的是Bar中的printIndex函数,由于在构建第二个Bar对象时已经为静态字段bar赋值,所以静态变量bar此时有值,但实例变量index还是为缺省值0,输出Bar@4633c1aa和0,Foo构造函数完成,返回。

10、执行Bar的初始化代码块输出:Bar initialization,再执行Bar的构造函数输出Bar constructor,Bar@4633c1aa和100,Bar构造函数完成。

11、Object reference bar指向heap之中最后创建完成的Bar对象,此时第一个Bar的对象创建完成。

12、66行调用bar对象函数输出Bar@4633c1aa和100.

13、67行此时给bar引用从新赋值,又从步骤一重复全部过程,由于静态只实例化一次所以输出为:Foo initialization、Foo constructor、Bar@4633c1aa、0、Bar initialization、Bar constructor、Bar@4633c1aa、100

输出结果为:

//代码在65行建构第一个Bar对象 
Foo static 
//代码执行到41行建构第二个Bar对象 
Foo initialization 
Foo constructor 
null 

Bar initialization 
Bar constructor 
null 
100 
//代码执行到56行第二个Bar对象建构完,继续建构第一个Bar对象 
Bar static 
Foo initialization 
Foo constructor 
Bar@4633c1aa 

Bar initialization 
Bar constructor 
Bar@4633c1aa 
100 
//66行调用第一个Bar对象的函数输出结果 
Bar@4633c1aa 
100 
//67行此时第一个Bar对象执行完,给第一个Bar引用从新建构对象 
Foo initialization 
Foo constructor 
Bar@4633c1aa 

Bar initialization 
Bar constructor 
Bar@4633c1aa 
100


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值