为什么这段代码不能编译?
public class A {
public class B extends A {
public B(A a) { }
}
void foo() {
A a = new A();
new B(a) { };
}
}
Run Code Online (Sandbox Code Playgroud)
A.java:[7,17] cannot reference this before supertype constructor has been called
如果进行以下任一更改,则编译成功:
B 是私人的而不是公共的new B(A);而不是new B(A) { }使用javac版本:1.6.0_20
pol*_*nts 20
应该注意的是,Eclipse
javac和Intellij IDEA在这些片段方面表现出不同的行为.javac并且Java Puzzlers行为在本讨论中用作参考.
我能够将片段剪切为以下内容:
public class A {
class B extends A {
}
void foo() {
new B() { }; // DOES NOT COMPILE!!
}
}
Run Code Online (Sandbox Code Playgroud)
这个场景在Java Puzzlers,Puzzle 90中讨论过:它是荒谬的,它是一个痛苦,它是超类!
给出的片段如下:
public class Outer { // "A"
class Inner1 extends Outer {} // "B"
class Inner2 extends Inner1 {} // "B" anonymous
}
// DOES NOT COMPILE!!
Run Code Online (Sandbox Code Playgroud)
问题是由于如何定义默认构造函数,我们确实有以下内容:
// Same as above but with default constructor included explicitly
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { super(); }
}
}
// STILL DOES NOT COMPILE!!
Run Code Online (Sandbox Code Playgroud)
问题是Inner2超类本身就是一个内部类Inner1,因此Inner2它的默认构造函数是非法的,因为它需要将一个封闭的实例提供给构造函数.
解决问题的"强力"方法是明确地提供一个限定this表达式:
// "brute-force" fix
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { Outer.this.super(); }
}
}
// NOW COMPILES!
Run Code Online (Sandbox Code Playgroud)
然而,这个谜题规定,首先要避免这种复杂的情况.以下是一些引用:
这编译,但它是令人难以置信的复杂.有一个更好的解决方案:每当你编写一个成员类时,问问自己,这个类真的需要一个封闭的实例吗?如果答案是否定的,那就去吧
static.内部类有时是有用的,但它们很容易引入使程序难以理解的复杂性.它们与泛型(Puzzle 89),反射(Puzzle 80)和继承(这个难题)有着复杂的相互作用.如果声明Inner1是static,问题消失.如果你还声明Inner2是static,你实际上可以理解程序在做什么:一个不错的奖金确实如此.总之,一个类很少适合作为另一个类的内部类和子类.更一般地说,扩展内部阶级很少是合适的; 如果你必须,请仔细思考封闭的实例.此外,更喜欢
static嵌套类到非static.大多数成员类都可以并且应该被声明static.