Java高级谜题90:荒谬痛苦的超类

Java高级谜题90:荒谬痛苦的超类,第1张

Java高级谜题90:荒谬痛苦的超类,第2张

下面的程序实际上不会做任何事情。更糟糕的是,它甚至不能被编译。为什么?怎么修改?
公共类Outer {
类Inner1扩展Outer{}
类Inner2扩展Inner1{}
}

这个程序看起来非常简单,不可能有任何错误,但是如果您尝试编译它,您会得到以下有用的错误消息:
outer.java: 3:在调用超类型构造函数之前无法引用它
class inner 2 extends inner 1 { }

好吧,也许这个消息没那么有用,但还是从这里开始吧。问题是编译器生成的默认Inner2的构造函数找不到合适的外部类实例给它的超级调用。我们来看看这个显式包含一个构造函数的程序:
public class outer {
public outer(){ }
class inner 1扩展outer {
public inner 1(){
super();//调用Object()构造函数
}
}
class inner 2 extends inner 1 {
public inner 2(){
Super();//调用Inner1()构造函数
}
}
}

现在错误消息会多显示一点信息:
outer.java: 12:在调用
超类型构造函数
super()之前不能引用这个;//调用Inner1()构造函数
]

因为Inner2的超类本身也是内部类,所以出现了一个晦涩的语言规则。众所周知,如果要实例化一个内部类,比如类Inner1,需要给构造函数提供一个外部类的实例。一般是隐式传递给构造函数,但也可以以expression . super(args)[JLS 8 . 8 . 7]的形式通过超类构造函数invovation显式传递。如果外部类实例是隐式传递的,编译器将自动生成一个表达式:它用这个来引用其超类是成员变量的最里面的外部类。这有点绕,但编译器就是这么做的。在这个例子中,超类是Inner1。因为当前类Inner2间接扩展了外部类,所以Inner1是它的继承成员。因此,超类构造函数的限定表达式直接是这个。编译器提供了一个外部类实例,将super重写为this.super这里解释的编译错误的含义可以扩展为:
outer.java: 12:在
超类型构造函数被调用之前无法引用this
this . super();
^

现在问题很清楚了:默认的Inner2构造函数试图在超类构造函数被调用之前访问它,这是非法操作[JLS 8.8.7.1]。解决这个问题的蛮力方法是显式传递一个合理的外部类实例:
public class outer {
class inner 1 extends outer { }
class inner 2 extends inner 1 {
public inner 2(){
outer . this . super .
}
}
}

这个可以编,但是太复杂了。这里有一个更好的解决方案:每当你写一个成员类的时候,问问自己这个成员类是否真的需要使用它的外部类实例?如果答案是否定的,那么应该将其设置为静态成员类。类有时非常有用,但它们很容易增加程序的复杂性,从而难以理解程序。它们以复杂的方式与泛型(难题89)、反射(难题80)和继承(这个难题)相互作用。在本例中,如果将Inner1设置为static,就可以解决这个问题。如果你也将Inner2设置为static,你会真正理解这个程序做了什么:这确实是一笔不错的意外之财。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » Java高级谜题90:荒谬痛苦的超类

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情