Java JVM如何启动超类和子类中的字段?

Java JVM如何启动超类和子类中的字段?,java,jvm,jls,Java,Jvm,Jls,任何人都能说出为什么下面代码的输出是“null”吗?构造复杂对象并将细节委托给其子类的最佳方法是什么 package com.test; public class ClassA { ClassA() { initHeader(); initBody(); initFooter(); } void initHeader() {} void initBody() {} void initFooter(

任何人都能说出为什么下面代码的输出是“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();
    }

}



首先,初始化
ClassA
的字段

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


然后,初始化
ClassB
的字段,覆盖
initHeader()
所做的操作。

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

public Object obj=null包含两部分:

  • 声明
    public Object obj
  • 执行
    obj=null
  • 构造函数运行时已知的第一部分(此时obj默认初始化为
    null
    ) 第二部分在构造函数之后执行,因此在
    initHeader之后执行
    ,并覆盖obj


    尝试只替换
    公共对象obj=null通过
    公共对象obj

    有趣的是,有人否决了唯一正确的答案(几乎是:调用了ClassB的构造函数,但因为它调用了super,所以也调用了ClassA的构造函数)!如果怀疑调试器是你的朋友-这正是正在发生的事情。由于我的upvote,投票结果现在是0。@mantrid我确信在编写一个漂亮(可读)的答案帮助方面做了一些努力。那么,构建复杂对象以避免这种混乱的最佳实践是什么呢?@AaronMao您所做的大部分都是好的,即使我个人尽可能限制复杂初始化的使用(或函数)使用多个层次结构级别。只需将
    公共对象obj=null;
    更改为
    公共对象obj;
    (正如xvorsx建议的那样)即可解决此问题@AaronMao:有一条一般规则:避免从构造函数调用非私有/非最终方法。构造复杂对象的最佳方法是什么…?-->保持简单实际上,第二部分在超级构造函数之后执行,然后子类构造函数执行。