【问题标题】:Array initialized at declaration not actually initialized until after call to super constructor声明时初始化的数组直到调用超级构造函数后才真正初始化
【发布时间】:2014-05-20 22:42:46
【问题描述】:

我遇到了一个看似奇怪的问题,尽管我知道这种设计背后可能有一些原因,并且想知道为什么会这样。

考虑两个类,Foo 和 Bar。 Bar 扩展了 Foo 并覆盖了 Foo 实现的方法。 Foo 很简单:

public class Foo {
    public Foo() {
        System.out.println("Foo constructor");
        someMethod();
    }

    public void someMethod() {
        System.out.println("Foo.someMethod");
    }
}

酒吧是问题所在。它定义了一个在构造函数之外初始化的数组(我不知道这个术语是什么)。我注意到当从 Foo 调用 someMethod 时,数组还没有被初始化,但是在调用 super() 之后,数组被初始化了。这里是酒吧:

public class Bar extends Foo {
    int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    public Bar() {
        super();
        System.out.println("FooBar constructor");
        if (a == null) System.out.println("FooBar a is null");
    }

    public void someMethod() {
        if (a == null) System.out.println("FooBar.someMethod a is null");
    }
}

这不太合理。我想从在超级构造函数中调用的方法访问数组,但数组未初始化。我试图想出一个解决方案。我的第一个想法是在 Bar 的构造函数中初始化数组,但在调用 super 之前仍然不会初始化它。

供参考,输出如下:

Foo constructor
FooBar.someMethod a is null
FooBar constructor

为什么 Java 会这样设计,最好的解决方法是什么?

【问题讨论】:

  • This doesn't quite make sense. 你为什么这么认为?当我父亲出生时,我的任何部分都存在吗?
  • 另外,这个What's wrong with overridable method calls in constructors? 会回答你的大部分问题。
  • 除此之外,它只是一个语法糖:数组的初始化发生在Bar的构造函数中,并且第一次调用必须是超级构造函数。因此,在调用 super 时,数据尚未初始化
  • 就是这样。初始化调用超级构造函数,然后初始化数组,然后调用子构造函数。
  • 您实际上可以通过将 a 的 init 移动到子构造函数中来更改它,然后让子构造函数调用 super() 数组已初始化。

标签: java oop


【解决方案1】:

超类构造函数必须在子类构造函数的其余部分开始之前成功完成。只有这样子类变量才会被初始化,所以在超类构造过程中,Bar中的a仍然是null。之所以出现这种奇怪的情况,是因为在子类中重写了由超类构造函数调用的方法,因此在子类本身初始化之前调用了子类方法。

更多关于它为什么不好的信息Java leaking this in constructor。这使得未完全初始化的对象可以被其他对象访问。

最好的办法是不要让超类的构造函数调用在子类中被覆盖的方法。如果愿意,让Bar 自己初始化/操作a

【讨论】:

    【解决方案2】:

    超类的构造函数必须在子类构造函数完成之前完成。这将包括任何初始化。

    【讨论】:

      猜你喜欢
      • 2013-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      • 2013-02-10
      相关资源
      最近更新 更多