考虑以下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;
}
}
代码将无法编译,编译器抱怨我上面突出显示的行。为什么会发生此错误以及最佳解决方法是什么?
答案 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在内存中加载声明,但没有构造函数可以在完全执行之前到达任何实例变量/字段。