Java “的奇怪情况;在调用超类型构造函数之前无法引用此;
为什么这段代码不编译Java “的奇怪情况;在调用超类型构造函数之前无法引用此;,java,Java,为什么这段代码不编译 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]在调用超类型构造函数之前无法引用此 如果进行以下任一更改,则编译成功: B是私有的,而不是公共的 第7行显示为新的B(A)而不是新的B(A){}
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]在调用超类型构造函数之前无法引用此
如果进行以下任一更改,则编译成功:
B
是私有的,而不是公共的
- 第7行显示为新的B(A)代码>而不是
新的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!!
}
}
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 explicitly
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { super(); }
}
}
// STILL DOES NOT COMPILE!!
这个场景在《谜题90》中进行了讨论:它是荒谬的,它是痛苦的,它是超类
给出的代码段如下所示:
public class A {
class B extends A {
}
void foo() {
new B() { }; // DOES NOT COMPILE!!
}
}
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 explicitly
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { super(); }
}
}
// STILL DOES NOT COMPILE!!
问题在于,由于默认构造函数是如何定义的,我们实际上有以下几点:
public class A {
class B extends A {
}
void foo() {
new B() { }; // DOES NOT COMPILE!!
}
}
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 explicitly
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { super(); }
}
}
// STILL DOES NOT COMPILE!!
问题是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!
然而,这个谜题规定,首先最好避免这种复杂的情况。以下是一些引文:
这是一个汇编,但它是令人麻木的复杂。有一个更好的解决方案:每当您编写一个成员类时,问问自己,这个类真的需要一个封闭的实例吗?如果答案为否,则将其设置为静态。内部类有时是有用的,但它们很容易引入使程序难以理解的复杂性。它们与泛型(谜题89)、反射(谜题80)和继承(这个谜题)有复杂的交互作用。如果将Inner1
声明为static
,则问题将消失。如果您还将Inner2
声明为static
,您实际上可以理解该程序的功能:这确实是一个不错的奖励
总之,将一个类同时作为另一个类的内部类和子类是不合适的。更一般地说,扩展一个内部类是不合适的;如果必须,请仔细考虑封闭实例。另外,与非静态类相比,更喜欢静态类
嵌套类。大多数成员类可以而且应该声明为静态的
不确定目标到底是什么,但试试这个。注意,我还删除了作为参数传递的非静态类,因为它们已经链接。我包括了引用外部类“this”的语法,因为在这些情况下,内部类可能会掩盖外部类字段/方法
public class A {
protected String field = "a";
public class B extends A {
protected String field = "b";
public B() {
System.out.println("" + A.this.field + " " + this.field);
}
@Override
void foo() {
System.out.println("b.foo()");
}
}
void foo() {
A a = new A();
a.field = "a2";
B b = a.new B() {
@Override
void foo() {
System.out.println("b.anon.foo()");
}
};
b.foo();
}
public static void main(String[] args) {
new A().foo();
}
}
运行此命令将输出:
a2 b
b.anon.foo()
希望这有帮助 你认为新的B(a){}
有什么作用?新的B(a){}应该实例化一个匿名的B子类,它的默认构造函数调用super(a)。显然,我试图编写的实际代码在该块中有重写方法-新的B(a){/*东西在这里*/}-但是为了简化这个问题,我删除了不必要的代码。这在Joshua Bloch的Java拼图中是90。在其示例章节中以#9的形式提供:。就我个人而言,即使在阅读了解决方案之后,我也无法理解它。我还将注意到Intellij IDEA与每个人都不一致——它认为所有这些代码都很好。axtavt链接的文档进一步简化了这一点。仅使用命名类:公共类A{class B扩展A{}类C扩展B{}这一次,即使IDEA也注意到了一些错误:“在调用超类型构造函数之前无法引用C.This”这是一个很好的答案-这在技术上是有意义的,而且,它的结论是绝对正确的:我遇到了麻烦,最终,因为B本来应该是静态的。我最终把我真实代码中的“B”变成了一个顶级类。