2013-02-25 103 views
5

有一个代码作为初级Java开发人员的任务给出。我在五年的使用Java和这段代码完全混淆了我:Java:对象的初始化顺序

public class Main { 

    String variable; 

    public static void main(String[] args) { 
     System.out.println("Hello World!"); 
     B b = new B(); 
    } 

    public Main(){ 
     printVariable(); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in Main Class"; 
    } 
} 

public class B extends Main { 

    String variable = null; 

    public B(){ 
     System.out.println("variable value = " + variable); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in B Class"; 
    } 
} 

输出将是:

Hello World! 
variable value = null 

但是,如果我们改变String variable = null;String variable;我们将有:

Hello World! 
variable value = variable is initialized in B Class 

第二个输出对我来说更加清晰。 所以,据我所知inizialisation的在Java中这样的顺序:

  • 我们去的类层次结构的根(用于Java它总是对象类),当我们来到这根父类:
    • 所有静态数据字段初始化;
    • 执行所有静态字段初始值设定项和静态初始化块;
    • 所有非静态数据字段被初始化;
    • 执行所有非静态字段初始化程序和非静态初始化块;
    • 默认的构造函数被执行;
  • 然后,我们不断为底层子类的程序。

也有帖子里面描述了一个超类的背景下this关键字的行为 - Calling base class overridden function from base class method

基于上面给出的规则,我认为有顺序是这样的:

  1. 我们将创建B类的新实例;
  2. 我们到部分类Main;
  3. 用null初始化main.variable;
  4. 然后我们转移到Main类的默认构造函数;
  5. 构造在Main类调​​用方法b.printVariable(); (为什么不调用它main.printvariable我们没有在这里this键字?)
  6. 领域b.variable变量是在B级初始化
  7. 现在我们再回到类B;
  8. 我们应该初始化场b.variable与空值,是吗?;
  9. B类的默认构造函数执行

请,能有人给的这种继承i​​nizialisation序列是如何工作的一个完整的,全面的解释。以及为什么更改String variable = null;String variable;导致另一个输出。

+1

printVariable(会发生什么)是一个非常误导的方法名字 - 应该更像setVariable( ) – Jimmt 2013-02-25 17:50:45

+1

你已经写了5年的Java,你不知道如何使用调试器? (单步执行代码会告诉你到底发生了什么以及按什么顺序)。 – 2013-02-25 18:04:55

+0

@BrianRoach当然,我可以使用debuger,我也试过javap -v -c B.class。但是每次当我看到java开发人员或面试问题的这些任务时,我都会尝试预测输出并理解它,为什么它会像这样工作,以及如果稍微修改代码会发生什么情况。逐步进行并没有解释执行过程的规则和原因。 – INlHELL 2013-02-27 09:58:32

回答

8

的顺序是:

  1. 首页 - > “你好”
  2. 首页 - >新B()
  3. B() - > Main() - > b.printVariable() - >设置变量
  4. 返回初始值ng B,所以变量= null发生。

所以基本上,超级对象Main()是在类B的任何初始化事件之前构造的。这意味着变量= null会在稍后发生。这是有道理的,否则B可能会破坏Main的初始化。

Joshua Bloch在他有效的java书中介绍了很多有关如何危险继承得到正确的好地方,我会推荐它。

+0

非常感谢你的解释,也非常感谢你提到的这本书,我会再仔细阅读一次。 – INlHELL 2013-02-27 10:10:59

2

首先,您需要了解当您编写variable = null;时会发生什么。该代码何时执行。这基本上决定了输出。

在开始之前,我还要提到,当您创建一个对象class B时,主类的printVariable()函数不会被调用。相反,总是会调用B的printVariable()

记住这一点,当你有variable = null时,B的构造函数的执行将开始。将调用第一个Main(),它将调用printVariable()方法。最后,variable=null,将被称为覆盖variable变量。

在另一种情况下,如果您未初始化variable=nullprintVariable()函数设置的variable不会被覆盖,因此您会得到您所期望的。

总之,这是语句的执行顺序,当你做new B()

Main()  //super constructor 
    B#printVariable() 
    initializtion of variables in B's constructor (if any) [i.e. variable=null, if present] 
+0

非常感谢你,你的解释完全澄清此代码。我没有得到,有可能以这种方式初始化字段: super_class-> method_of_child_class-> field_of_child_class 并且该字段可能会在儿童初始化过程中被覆盖(如果字段不为空)类。 – INlHELL 2013-02-27 10:25:33

1

这是一个不错的练习!但问初级开发人员这不是一个公平的问题。这是一个老年人。

public Main(String something){ 
printVariable(); 
} 

如果这个人会回答会发生什么,然后取出参数,并要求原始的问题:但是,为了使这个文本的技术面试过程中非常有用,我会通过添加参数传递给主要的构造函数修改了它。如果这个人不回答 - 就没有必要继续 - 他/她是初中。

您还可以删除在B级受保护的资格,并询问如果你有一个目标,不雇佣这个人:)