超types构造函数被调用之前不能引用“X”,其中x是最后一个variables
考虑下面的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; } }
编译器不会编译,抱怨上面突出显示的那一行。 为什么这个错误发生,什么是最好的解决方法?
代码最初不能编译的原因是因为defaultValue
是类Test
一个实例variables ,这意味着当一个Test
types的对象被创build时,一个唯一的defaultValue
实例也被创build并被附加到该特定对象上。 因此,在构造函数中引用defaultValue
是不可能的,因为它既没有创build对象,也没有创build对象。
解决的办法是让最后一个variablesstatic
:
public class Test { private static final int defaultValue = 10; private int var; public Test() { this(defaultValue); } public Test(int i) { var = i; } }
通过将variables设置为static
variables,variables与类本身相关联,而不是该类的实例,并在Test
所有实例中共享。 静态variables在JVM首次加载类时创build。 由于类在您使用它创build实例时已经加载,因此可以使用静态variables,因此可以在类中使用,包括构造函数。
参考文献:
- 论坛post问同样的问题
- 了解实例和类成员
- 类加载器如何加载静态variables的说明
这是因为defaultValue
是正在构build的Test
实例的成员(尚未创build)
如果你是static
,当你的类加载类加载器时,它会被加载
规则:每个构造函数在执行之前都必须执行超类的构造函数。
因此,每个构造函数的第一行是super()或者可能是this(),并且您将defaultValue发送给此类构造函数,该函数的defaultValue不存在,因此存在编译时错误。
您可以将defaultValue设置为static,并且由于将类加载到内存中时创build静态variables,所以defaultValue在this(defaultValue)行可用。
直到你的对象没有被构造,variables的默认值将不会被设置,因此如果你希望在构造时设置它们的默认值,使它们成为static
或者明确地设置它们。
构造函数在对象创build时被调用,所以编译器不会识别可变参数,因为编译器没有关于实例variables的知识,因为对象还没有被创build。
其实这是不正确的答案,因为在创build对象期间,字段初始化指令在构造函数之前执行。 您可以debugging对象创build过程并自行查看。 我自己也对这个问题感到困惑。例如,如果你会改变一点,第一个构造函数将是:
public Test(int i) { this(i, 0); } public Test (int a, int k) { }
这将工作..所以,当第一个/空构造函数调用另一个,它不工作的一个奇怪的原因,即使我显式调用super(); 之前。
最相关的解释是,JVM在内存中加载声明,但是在它完全执行之前,没有任何构造者可以达到任何实例variables/字段 。
你正在引用一个不存在的variables,如果它是静态的,所以它甚至会在构造函数本身之前存在
但你会面临另一个问题,因为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; } }
在这个话题下,我一直在关注这个问题。
class Super{ int a=10; static int x=100; Super(){ System.out.println("Super()"); } Super(int i){ System.out.println("Super(int)"); } } class Sub extends Super{ int b=20; static int y=20; Sub(int i){ ***Super(b);*** System.out.println("Sub(int)"); } }
super和sub类的实例variables,我们不能用于引用。 因为实例variables是在构造函数运行之后初始化的。 而variables不是最终的和静态的。 值可以改变。 以及这些只有实例variables,因此我们碰巧创build对象来初始化这个variables。所以这个variables不能用于引用。 但是如果这个variables是最终的和静态的,那么这些variables只保留模板。 以及这些variables具有特定的值,这些不变。 因此,我们可以调用超类构造函数使用这些静态最终variables。