【问题标题】:How does the JVM initiate the fields in super and sub classes?JVM如何初始化超类和子类中的字段?
【发布时间】:2013-02-07 07:47:24
【问题描述】:

任何人都可以说出为什么以下代码的输出为“null”吗?构造复杂对象并将细节委托给其子类的最佳方法是什么?


package com.test;

public class ClassA {

    ClassA() {
        initHeader();
        initBody();
        initFooter();
    }

    void initHeader() {}

    void initBody() {}

    void initFooter() {}

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

class ClassB extends ClassA {

    public Object obj = null;

    ClassB() {
        super();
    }

    void initHeader() {
        obj = new Object();
    }

}


【问题讨论】:

  • 构造一个复杂对象的最佳方法是什么...? --> 保持简单

标签: java jvm jls


【解决方案1】:

首先,ClassA的字段被初始化。

然后调用ClassA的构造函数,调用ClassB.initHeader()

之后,ClassB 的字段被初始化,覆盖 initHeader() 所做的事情。

【讨论】:

  • 有趣的是有人否决了唯一正确的答案(几乎:ClassB 的构造函数被调用,但由于它调用 super,ClassA 的构造函数也被调用)!如果有疑问调试器是您的朋友 - 这正是正在发生的事情。由于我的支持,投票现在为 0。
  • @mantrid 我确信在编写漂亮(且可读)的答案帮助方面付出了一些努力。
  • 那么,构造复杂对象以避免这种混淆的最佳实践是什么?
  • @AaronMao 你所做的大部分都很好,即使我个人尽可能地尝试使用多个层次结构来限制复杂初始化(或函数)的使用。只需将 public Object obj = null; 更改为 public Object obj; 即可修复它(正如 xvorsx 所建议的那样)。
  • @AaronMao:有一个通用规则:避免从构造函数调用非私有/非最终方法。
【解决方案2】:

这段代码没有从 ClassB 调用 initHeader 是不正确的。 您可以通过将调试输出添加到两个类的initHeader 方法来验证它。

public Object obj = null; 包含两部分:

  1. 声明public Object obj
  2. 执行obj = null

构造函数运行时已知的第一部分(此时obj默认初始化为null) 第二部分执行在构造函数之后,所以在initHeader 之后并覆盖obj。

尝试将public Object obj = null; 替换为public Object obj;

【讨论】:

  • 其实第二部分在超级构造函数之后执行,然后子类构造函数执行。
猜你喜欢
  • 2011-03-16
  • 2020-02-05
  • 1970-01-01
  • 1970-01-01
  • 2016-12-30
  • 2013-07-27
  • 2011-04-11
  • 2017-01-09
  • 1970-01-01
相关资源
最近更新 更多