Java解析三个java对象初始化顺序难题

http://jm.taobao.org/2010/07/21/331/ 

 

昨菲律宾人在Dzone阅读了一篇有关java对象实例起头化顺序的幽默文章。说它有趣,是因为笔者利用了一种并不太推荐的编码风格,惟有用那种编码风格才能接触这么些颇为少见的
Java object initialization order 难题。

实际上java对象初叶化顺序算是贰个相比基础的java知识点。不过网上的篇章多半描述不清,使用上一相当大心就不难出难题。
因而在本文中,作者想结合JLS和调谐的知情,举例剖析难题的到处。

OK,大家先来看个模仿Dzone小编原意的简便例子:
[java]
package com.kenwublog.tmp;

public class A extends B {
public int a = 100;

public A() {
    super();
    System.out.println(a);
    a = 200;
}

public static void main(String[] args) {
    System.out.println(new A().a);
}

}

class B {
public B() {
System.out.println(((A) this).a);
}
}
[/java]
事例代码很简短,不多做表达了,直接看输出:
0
100
200

相对而言那个输出,大家来详细分析一下目的的开首化顺序:
1,为A类分红内部存款和储蓄器空间,开首化全数成员变量为暗中同意值,包蕴primitive类型(int=0,boolean=false,…)和Reference类型。
2,调用A类构造函数。
3,调用B类构造函数。
4,调用Object空构造函数。(java编写翻译器会暗许加此构造函数,且object构造函数是个空函数,所以即刻回去)
5,开始化B类成员变量,因为B类没有成员变量,跳过。
6,执行sysout输出子类A的积极分子变量小a。// 此时为0
7,初步化A类成员变量,将A类成员变量小a赋值100。
8,执行sysout输出当前A类的积极分子变量小a。// 此时为100
9,赋值当前A类的积极分子变量小a为200。
10,main函数中实践sysout,输出A类实例的积极分子变量小a。// 此时为200

加粗的那两行描述是重中之重,结论是成员变量初叶化是在父类构造函数调用完后,以前,成员变量的值均是默许值。 Dzone作者正是栽在那边,没有仔细分析成员变量初始化在对象开端化中的顺序,造成了程序未按原意执行。
实在那类难点,熟稔原理是一边,本质上一旦不在构造函数中插入过多的事务逻辑,出标题的可能率也会低很多。

末段,大家再来看看JLS中提交的Java类对象初叶化顺序定义,那是三个带条件分支的流程描述:

  1. Assign the arguments for the constructor to newly created parameter
    variables for this constructor invocation.
  2. If this constructor begins with an explicit constructor invocation
    of another constructor in the same class (using this), then
    evaluate the arguments and process that constructor invocation
    recursively using these same five steps. If that constructor
    invocation completes abruptly, then this procedure completes
    abruptly for the same reason; otherwise, continue with step 5.
  3. This constructor does not begin with an explicit constructor
    invocation of another constructor in the same class (using this).
    If this constructor is for a class other than Object, then this
    constructor will begin with an explicit or implicit invocation of a
    superclass constructor (using super). Evaluate the arguments and
    process that superclass constructor invocation recursively using
    these same five steps. If that constructor invocation completes
    abruptly, then this procedure completes abruptly for the same
    reason. Otherwise, continue with step 4.
  4. Execute the instance initializers and instance variable initializers
    for this class, assigning the values of instance variable
    initializers to the corresponding instance variables, in the
    left-to-right order in which they appear textually in the source
    code for the class. If execution of any of these initializers
    results in an exception, then no further initializers are processed
    and this procedure completes abruptly with that same exception.
    Otherwise, continue with step 5. (In some early implementations, the
    compiler incorrectly omitted the code to initialize a field if the
    field initializer expression was a constant expression whose value
    was equal to the default initialization value for its type.)
  5. Execute the rest of the body of this constructor. If that execution
    completes abruptly, then this procedure completes abruptly for the
    same reason. Otherwise, this procedure completes normally.
    引用自 section 12.5 of the Java Language
    Spec

相关文章