83

考虑以下 Java 类声明:

public class Test {

    private final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);    // <-- Compiler error: cannot reference defaultValue before supertype constructor has been called.
    }

    public Test(int i) {
        var = i;
    }
}

代码将无法编译,编译器会抱怨我在上面突出显示的行。为什么会发生此错误,最好的解决方法是什么?

4

6 回答 6

113

代码最初不会编译的原因是因为defaultValue是类的实例变量Test,这意味着当创建类型的对象时,Test也会创建一个唯一的实例defaultValue并将其附加到该特定对象。因此,无法defaultValue在构造函数中引用,因为它和对象都尚未创建。

解决方案是制作最终变量static

public class Test {

    private static final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);
    }

    public Test(int i) {
        var = i;
    }
}

通过创建变量static,它与类本身相关联,而不是与该类的实例相关联,并在 的所有实例之间共享Test。静态变量是在 JVM 首次加载类时创建的。由于当您使用它创建实例时该类已经加载,因此静态变量已准备好使用,因此可以在类中使用,包括构造函数。

参考:

于 2012-06-09T19:06:20.407 回答
9

这是因为是正在建设中(尚未创建)的实例defaultValue的成员Test

如果你有它,static它是在类加载器加载你的类时加载的

于 2012-06-09T19:08:03.130 回答
6

您正在引用一个尚不存在的变量,如果它是静态的,它甚至会在构造函数本身之前存在。

但是您将面临另一个问题,因为它defaultValue变成静态的,因此所有其他实例可能共享您可能不喜欢的相同值:

public class Test {

    private final int defaultValue = 10; //this will exist only after calling the constructor
    private final static int value2= 10; //this exists before the constructor has been called
    private int var;

    public Test() {
       // this(defaultValue);    // this method will not work as defaultValue doesn't exist yet
    this(value2); //will work
    //this(10); will work
    }

    public Test(int i) {
        var = i;
    }
}
于 2017-08-06T20:00:36.277 回答
4

规则:每个构造函数必须在执行自身之前执行超类的构造函数。

所以每个构造函数的第一行是 super() 或者可能是 this() 并且你将 defaultValue 发送到 this 类构造函数 which(defaultValue) 尚不存在,因此存在编译时错误。

您可以将 defaultValue 设为静态,并且由于静态变量是在将类加载到内存时创建的,因此 defaultValue 在 this(defaultValue) 行中可用。

于 2012-06-09T19:42:39.493 回答
1

在未构造对象之前,不会设置变量的默认值,因此,如果您希望在构造时设置它们的默认值,请先设置它们static或显式设置它们。

于 2012-06-09T20:03:37.877 回答
0

在创建对象时调用构造函数,因此编译器不会识别对变量的引用,因为编译器不知道实例变量,因为尚未创建对象。

于 2017-06-14T10:24:01.950 回答