【问题标题】:Java: initialization sequence of objectJava:对象的初始化序列
【发布时间】:2013-02-25 17:45:26
【问题描述】:

有一个代码是作为初级 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

第二个输出对我来说更清楚。 因此,据我所知,Java 中的初始化顺序如下:

  • 当我们来到这个根父类时,我们转到类层次结构的根(对于 Java,它始终是 Object 类):
    • 所有静态数据字段均已初始化;
    • 所有静态字段初始化器和静态初始化块都被执行;
    • 所有非静态数据字段均已初始化;
    • 执行所有非静态字段初始化器和非静态初始化块;
    • 执行默认构造函数;
  • 然后我们对底层子类重复该过程。

还有一篇文章描述了this 关键字在超类上下文中的行为 - Calling base class overridden function from base class method

根据上面给出的规则,我假设有这样的顺序:

  1. 我们将创建一个类B的新实例;
  2. 我们去零件课Main;
  3. 用空值初始化main.variable
  4. 然后我们转到Main类的默认构造函数;
  5. 构造函数在类Main中调用方法b.printVariable(); (为什么不叫main.printvariable?我们这里没有this关键字。)
  6. 字段b.variable变量在B类中初始化
  7. 现在我们回到课堂B
  8. 我们应该用空值初始化字段b.variable,对吗?;
  9. B的默认构造函数已执行

请,有人可以对这个继承初始化序列是如何工作的给出完整和完整的解释。以及为什么将String variable = null; 更改为String variable; 会导致另一个输出。

【问题讨论】:

  • printVariable() 是一个非常容易误导的方法名称 - 应该更像 setVariable()
  • 你写java已经5年了,你还不知道调试器怎么用? (单步执行您的代码将向您确切显示正在发生的事情以及发生的顺序)。
  • @BrianRoach 当然我可以使用调试器,我还尝试了 javap -v -c B.class。但是每次当我看到 Java 开发人员的此类任务或面试问题时,我都会尝试预测输出并理解它,为什么它会这样工作以及如果我稍微修改代码会发生什么。单步执行并没有说明执行过程的规律和原因。

标签: java oop inheritance


【解决方案1】:

顺序是:

  1. 主要 -> “你好”
  2. 主 -> 新 B()
  3. B() -> Main() -> b.printVariable() -> 设置变量
  4. 回到初始化 B,因此出现 variable=null。

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

Joshua Bloch 在他有效的 Java 书籍中涵盖了很多好的基础,关于正确继承是多么危险,我会推荐它。

【讨论】:

  • 非常感谢您的解释,也非常感谢您提到的这本书,我会再仔细阅读一遍。
【解决方案2】:

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

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

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

在另一种情况下,如果您不初始化variable=null,则printVariable() 函数设置的variable 不会被覆盖,因此您会得到预期的结果。

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

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

【讨论】:

  • 非常感谢,您的解释完全阐明了这段代码。我没有得到的是,有可能以这种方式初始化字段:super_class->method_of_child_class->field_of_child_class,并且在初始化子类期间该字段可能会被覆盖(如果该字段不为空)。跨度>
【解决方案3】:

这是一个很好的练习!但问初级开发人员不是一个公平的问题。这个是给老年人的。但是为了让这段文字在技术面试中有用,我修改了它,在 Main 的构造函数中添加了一个参数:

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

如果该人会回答将要发生的事情,则删除论点并提出原始问题。如果对方不回答 - 无需继续 - 他/她是初级。

您还可以删除 B 类中受保护的限定词,并询问如果您的目标是不雇用此人会发生什么:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多