在JAVA中,由于内部类的构建器必须连接到指向其外围类对象的引用,所以在继承内部类的时候会变得很复杂。问题在于指向外围类对象的秘密引用必须得到初始化,而在导出类中不再存在可连接的默认对象,我们必须使用特殊的语法来明确说明它们的关系:
enclosingClassReference.super()。
看如下一段代码:
package access;
class WithInner{
class Inner{}
}
public class InheritInner extends WithInner.Inner{
InheritInner(WithInner x){
x.super();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
WithInner x = new WithInner();
InheritInner i = new InheritInner(x);
}
}
可以看到InheritInner只继承了内部类,并没有继承外围类,但若要生成一个构建器时,默认的构建器并不能完成此工作,不能只是传递一个指向外围类对象的引用,必须提供上述语法来确定一个关系。
如果我们创建了一个内部类,然后继承其外围类并重新定义内部类的时候会发生什么?看上去这和覆盖某种方法类似,但实际则不然,覆盖内部类就好像是外围类的一个方法,实际上并不起什么作用,看如下一段代码:
package access;
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){
System.out.println("Egg.Yolk()");
}
}
public Egg(){
System.out.println("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg{
public class Yolk{
public Yolk(){
System.out.println("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new BigEgg();
}
}
此程序的运行结果为:
我们可能会与覆盖方法所混淆,认为既然创建了BigEgg的对象,那么所使用的应该是覆盖后的Yolk方法,但从输出来看并不是这样,当创建BigEgg对象时,构建器只是会先调用Egg的构建方法来初始化一个Egg,所以所有的输出均来自于Egg,而我们在BigEgg中并没有调用任何的方法来操纵BigEgg中的Yolk方法,只有当出现调用时,才会发生输出,改动一下此代码:
package access;
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){
System.out.println("Egg.Yolk()");
}
}
public Egg(){
System.out.println("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg{
private Yolk x;
public class Yolk{
public Yolk(){
System.out.println("BigEgg.Yolk()");
}
}
public BigEgg(){
System.out.println("New BigEgg()");
x = new Yolk();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new BigEgg();
}
}
此程序的输出结果为:
可以看到只有在实际发生调用时候才会进行输出,这与方法覆盖有着本质的区别。
当我们继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化,内部类是完全独立的实体,各自在自己的命名空间内,看如下一段代码:
package access;
class Egg2{
protected class Yolk{
public Yolk(){
System.out.println("Egg2.Yolk()");
}
public void f(){
System.out.println("Egg2.Yolk().f()");
}
}
private Yolk y = new Yolk();
public Egg2(){
System.out.println("New Egg2()");
}
public void insertYolk(Yolk yy){
y = yy;
}
public void g(){
y.f();
}
}
public class BigEgg2 extends Egg2{
public class Yolk extends Egg2.Yolk{
public Yolk(){
System.out.println("BigEgg2.Yolk()");
}
public void f(){
System.out.println("BigEgg2.Yolk.f()");
}
}
public BigEgg2(){
insertYolk(new Yolk());
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Egg2 e2 = new BigEgg2();
e2.g();
}
}
此程序的输出结果为:
可以看到的是BigEgg2.Yolk通过继承Egg2.Yolk明确继承了内部类并覆盖了其中的方法。
insertYolk方法现在允许BigEgg2将自己的Yolk对象上转型为Egg2中的引用y,所以当g()调用y.f()时,覆盖后的f()被执行。
第二次调用Egg2.Yolk,结果是BigEgg2.Yolk的构建器调用了基类的构建器。
输出结果的前两行是在创建BigEgg2对象的时候首先对基类进行初始化的结果,第三行是在创建BigEgg2时调用基类的insertYolk方法时重新对y进行构建的结果,最后两行是在用上转型的Egg2引用操作对象BigEgg2时调用继承过来的内部类方法的结果。