“在调用超类型构造函数之前无法引用此”的奇怪情况
为什么此代码无法编译?
public class A { public class B extends A {
public B(A a) { }
}
void foo() {
A a = new A();
new B(a) { };
}
}
A.java:[7,17] cannot reference this before supertype constructor has been
called
如果进行以下任一更改,则编译成功:
B
是私人的而不是公共的- 第7行读取,
new B(A);
而不是new B(A) { }
使用Javac版本:1.6.0_20
回答:
应该注意的是,Eclipse
javac
和Intellij IDEA在这些代码片段方面表现出不同的行为。javac
和 Java的谜题行为被用于讨论参考。
我可以将代码段缩减为以下内容:
public class A { class B extends A {
}
void foo() {
new B() { }; // DOES NOT COMPILE!!
}
}
在 Java Puzzlers ,
Puzzle 90中 讨论了这种情况 :荒谬,痛苦,超类!
给出的代码段如下:
public class Outer { // "A" class Inner1 extends Outer {} // "B"
class Inner2 extends Inner1 {} // "B" anonymous
}
// DOES NOT COMPILE!!
问题在于,由于如何定义默认构造函数,我们实际上具有以下内容:
// Same as above but with default constructor included explicitlypublic class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { super(); }
}
}
// STILL DOES NOT COMPILE!!
问题在于,Inner2
超类本身是一个内部类Inner1
,因此使Inner2
的默认构造函数非法,因为它需要将封闭的实例提供给构造函数。
解决问题的“蛮力”方法是为它明确提供一个限定this
表达式:
// "brute-force" fixpublic class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { Outer.this.super(); }
}
}
// NOW COMPILES!
然而,难题规定,首先要避免这种复杂的情况。以下是一些引号:
这可以编译,但是令人难以理解。有一个更好的解决方案:每当您编写成员类时,请问自己:此类是否真的需要一个封闭实例?如果答案是否定的,请回答
static
。内部类有时很有用,但是它们很容易引入复杂性,使程序难以理解。它们与泛型(难题89),反射(难题80)和继承(此难题)具有复杂的交互。如果您声明Inner1
为static
,问题就解决了。如果您还声明Inner2
为static
,则实际上可以理解该程序的功能:确实是一个不错的奖励。总而言之,很少将一个类同时用作另一个的内部类和子类。更普遍地讲,扩展内部类很少是合适的。如果需要,请仔细考虑该封闭实例。此外,
static
与non-相比,更喜欢嵌套类
static
。可以并且应该声明大多数成员类static
。
以上是 “在调用超类型构造函数之前无法引用此”的奇怪情况 的全部内容, 来源链接: utcz.com/qa/427571.html