在调用超类型构造函数之前不能引用“X”,其中x是最终变量

时间:2012-06-09 19:05:17

标签: java constructor final supertype

考虑以下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;
    }
}

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

7 个答案:

答案 0 :(得分:86)

代码最初不能编译的原因是因为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首次加载类时会创建静态变量。由于在使用它来创建实例时已经加载了类,因此静态变量可以使用,因此可以在类中使用,包括构造函数。

参考文献:

答案 1 :(得分:8)

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

如果你有static,那么当你的类按类加载器

加载时它就被加载了

答案 2 :(得分:4)

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

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

您可以将defaultValue设置为static,因为在将类加载到内存时会创建静态变量,因此defaultValue在此行(defaultValue)处可用。

答案 3 :(得分:4)

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

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

public class Test {

    private final int defaultValue = 10; //this will be exists only after calling the contractor
    private final static int vakue2= 10; //this is exists before the contractor has been called
    private int var;

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

实际上这不是正确答案,因为在创建对象期间,字段初始化指令在构造函数之前执行。您可以调试对象创建过程并自行查看。我自己也对这个问题感到困惑..例如,如果你改变一点,第一个构造函数将是:

public Test(int i) {
   this(i, 0);
}
public Test (int a, int k) {
}

这样可以工作..所以,当第一个/ null构造函数调用另一个时,即使我明确地调用了super(),它也不会出于某种奇怪的原因而工作。之前。

最相关的解释是,JVM在内存中加载声明,但没有构造函数可以在完全执行之前到达任何实例变量/字段