奇怪的情况是“在调用超类型构造函数之前不能引用它” [英] Odd situation for "cannot reference this before supertype constructor has been called"
问题描述
为什么这段代码不能编译?
公共类A {
公共类B扩展A {
public B(A a){}
}
void foo(){
A a = new A();
new B(a){};
}
}
A.java:[ 7,17]在调用超类型构造函数之前无法引用它
如果进行了以下任一更改,编译成功:
-
B
是私有而非公开 - 第7行读取
新B(A);
而不是新B(A){}
使用javac版本:1.6.0_20
应该注意的是,Eclipse,
javac
和Intellij IDEA在这些片段方面表现出不同的行为。javac
和 Java Puzzlers 行为在本讨论中用作参考。
我能够将代码段减少到以下内容:
公共类A {
B类延伸A {
}
void foo(){
new B(){}; //没有编译!!
}
}
此方案在 Java Puzzlers ,拼图90:这是荒谬的,这是一种痛苦,它是超类!
给出的片段如下:
public class Outer {//A
class Inner1 extends Outer {} //B
class Inner2 extends Inner1 {} //Banonymous
}
//没有编译!!
问题是由于定义了默认构造函数,我们确实有以下内容:
//与上面相同但显式包含默认构造函数
public class Outer {
class Inner1 extends Outer {
Inner1(){super(); }
}
类Inner2扩展Inner1 {
Inner2(){super(); }
}
}
//仍然没有编译!
问题在于 Inner2
的超类本身是一个内部类 Inner1
,从而使 Inner2
的默认构造函数非法,因为它需要提供一个封闭的实例到了构造函数。
修复问题的强力方法是明确地提供一个限定的 - this
表达式:
//暴力破解修复
公共类外部{
class Inner1扩展了外部{
Inner1(){super(); }
}
类Inner2扩展Inner1 {
Inner2(){Outer.this.super(); }
}
}
//现在编译!
然而,这个谜题规定最好避免这种复杂的情况。以下是一些引用:
这是编译,但它是令人头疼的复杂。有一个更好的解决方案:每当你写一个成员类时,问问自己,这个类真的需要一个封闭的实例吗?如果答案是否定的,请将其设为
static
。内部类有时是有用的,但它们很容易引入使程序难以理解的复杂性。它们与泛型(Puzzle 89),反射(Puzzle 80)和继承(这个难题)有着复杂的相互作用。如果您将Inner1
声明为static
,则问题就会消失。如果你还宣布Inner2
为static
,你实际上可以理解程序的作用:确实是一个很好的奖励。 / p>
总之,一个类很少适合作为另一个类的内部类和子类。更一般地说,扩展内部阶级很少是合适的;如果必须,请仔细思考封闭的实例。另外,更喜欢
static
嵌套类到非static
。大多数成员类可以而且应该被声明为static
。
Why doesn't this code compile?
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
Compilation is successful if either of these changes are made:
B
is private instead of public- line 7 reads
new B(A);
instead ofnew B(A) { }
Using javac version: 1.6.0_20
It should be noted that Eclipse,
javac
, and Intellij IDEA exhibit differences in behaviors with regards to these snippets.javac
and the Java Puzzlers behavior is used for reference in this discussion.
I was able to cut down the snippet to the following:
public class A {
class B extends A {
}
void foo() {
new B() { }; // DOES NOT COMPILE!!
}
}
This scenario is discussed in Java Puzzlers, Puzzle 90: It's Absurd, It's a Pain, It's Superclass!
The snippet given is the following:
public class Outer { // "A"
class Inner1 extends Outer {} // "B"
class Inner2 extends Inner1 {} // "B" anonymous
}
// DOES NOT COMPILE!!
The problem is that due to how default constructor is defined, we really have the following:
// 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!!
The problem is that Inner2
's superclass is itself an inner class Inner1
, thus making Inner2
's default constructor illegal since it requires an enclosing instance to be supplied to the constructor.
The "brute-force" way to fix the problem is to provide this explicitly with a qualified-this
expression:
// "brute-force" fix
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { Outer.this.super(); }
}
}
// NOW COMPILES!
However, the puzzle prescribes that such complicated situation is best avoided in the first place. Here are some quotes:
This compiles, but it is mind-numbingly complex. There is a better solution: Whenever you write a member class, ask yourself, Does this class really need an enclosing instance? If the answer is no, make it
static
. Inner classes are sometimes useful, but they can easily introduce complications that make a program difficult to understand. They have complex interactions with generics (Puzzle 89), reflection (Puzzle 80), and inheritance (this puzzle). If you declareInner1
to bestatic
, the problem goes away. If you also declareInner2
to bestatic
, you can actually understand what the program does: a nice bonus indeed.In summary, it is rarely appropriate for one class to be both an inner class and a subclass of another. More generally, it is rarely appropriate to extend an inner class; if you must, think long and hard about the enclosing instance. Also, prefer
static
nested classes to non-static
. Most member classes can and should be declaredstatic
.
这篇关于奇怪的情况是“在调用超类型构造函数之前不能引用它”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!