在java中初始化final字段的奇怪行为

时间:2018-04-19 10:49:29

标签: java inheritance initialization

我有一个简单的Java程序:

Test2

实例化Test时,它的构造函数会调用foo的构造函数,后者会调用Test2中实现的方法foo

在执行testObj期间,字段null为{{1}},即使它是最终的。

这是正确的行为吗?如果是这样,是否有解决方案?

3 个答案:

答案 0 :(得分:2)

是的,这是正确的行为:派生类的foo()仅在超类初始化之后才被初始化;由于{<1}}在超级类初始化之前被称为testObj仍为null

解决此问题的最佳方法是不在构造函数中调用抽象方法,因为它们可能会发现它们的对象处于未初始化状态。另一种方法是将呼叫推迟到foo()。如果foo必须作为初始化序列的一部分被调用,因为它为基类提供了某些东西,它不应该访问实例上的任何状态。

答案 1 :(得分:0)

您正在调用Test2方法,而Test2尚未完成构建,只有对象的Test部分已完成。因此,Test2的实例变量尚未分配(幸运的是它们是null而不是一些随机内存指针!)

&#39;正确&#39;模式是不在基类中调用抽象方法&#39;构造函数,如果你真的不需要让该方法依赖于它的实例变量,而只依赖于参数。

答案 2 :(得分:0)

即使你没有将super()方法放在基类的构造函数中。编译器将自己放置super()方法。例如:

class A {
    A() {
        System.out.println("A");
    }
}

class B extends A {
    B() {
        System.out.println("B");
    }
}

class C extends B {
    C() {
        System.out.println("C");
    }
    public static void main(String[] args) {
        C c = new C();
    }
}

您可以通过在每个构造函数的第一行放置super()方法来重新检查上述函数。工作流程不会改变。还有另一个规则,即super()和this()方法将始终只放在构造函数的第一行。这是继承情况下java的工作流程。

现在回答你的问题。在创建Test2的实例时,在初始化testobj之前从构造函数中调用super()方法。因此,当从基类Test调用foo()方法时,testobj没有被初始化并调用函数,这就是为什么它显示为null。