package Day05_innerclass;
//: innerclasses/BigEgg2.java
// Proper inheritance of an inner class.
import static myutil.Print.print;
//import static net.mindview.util.Print.*;
class Egg2 {
protected class Yolk {
public Yolk() { print("Egg2.Yolk()"); }
public void f() { print("Egg2.Yolk.f()");}
}
private Yolk y = new Yolk();
public Egg2() { print("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() { print("BigEgg2.Yolk()"); }
public void f() { print("BigEgg2.Yolk.f()"); }
}
public BigEgg2() { insertYolk(new Yolk()); } // 如果注释这行, 发现 bigegg2 的内部类都没被构造,因为bigegg2 的new Yolk() 是优先在bigegg2下面找有没有,
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();// 此处在实例化e2 之前,会先看bigegg2, 先看 他的构造函数,发现构造函数之外,big先继承egg2, 所以向上寻找
// 找到egg2 的构造函数,然后发现有个 字段,其中有个new 内部类,于是先 对egg2 的内部类进行初始化,找到内部类的构造函数,构造函数之外没有字段
// 所以 egg2 的内部类的构造函数 执行, 回到egg2 类 的字段那里,private y=new yolk() 此时 y 有了初始值
// 所以执行 egg2 的构造函数
// 回到 bigegg2 的构造函数那里,基类egg2 以及 egg2 的内部类都已经准备好了,
// 但是,bigegg2构造函数之前,发现还有一个内部类,
e2.g();
}
} /* Output:
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
*///:~
如果把 BigEgg2 中的内部类注释掉:
发现BigEgg2没有因为自己没有内部类而报错,而是去内部的基类(父类)当中寻找Yolk类,并且进行相应的初始化
如果把 BigEgg2 中 InsertYolk()这行注释掉
可以看出BigEgg2 的内部类没有被使用到,因为注释掉
public BigEgg2() { insertYolk(new Yolk()); }
后,BigEgg2 的构造器使用的是默认的 BigEgg2()在BigEgg2 的作用域内没有明显调用 new Yolk()。因此, BigEgg2 的内部类也就没有被使用到,从而也就不必对其初始化。
总结:
1、在使用函数时的优先顺序:先是从导出类(子类)中寻找,如果子类中没有该函数,则会向父类寻求帮助(父类) (与多态类似)
2、内部类在使用到才会被初始化
3、在初始化时,一般都是会先看构造器,然后检查构造器之前有没有存在着 字段(域), (这些字段 相当于是 一些前置准备工作,准备好后,才会去执行构造函数)。如果字段又存在着调用,则又会看调用的是哪里的函数,在进行相应初始化,
例如:
class Egg2 {
protected class Yolk {
public Yolk() { print("Egg2.Yolk()"); }
public void f() { print("Egg2.Yolk.f()");}
}
private Yolk y = new Yolk();
public Egg2() { print("New Egg2()"); }
public void insertYolk(Yolk yy) { y = yy; }
public void g() { y.f(); }
}
在执行Egg2 的构造器之前,会先检查Egg2 下方的字段,发现了此处的private Yolk y = new Yolk(),从而 在Egg2 类的作用域当中寻找 Yolk类,也就是此处的内部类,在进行相应初始化。
4、内部类中的方法看似被重载,但是实际上确不是,因为Egg2的内部类Yolk和BigEgg2 下的Yolk实际上是两个相互独立的实体,他们各自有着自己的命名空间。
//: innerclasses/BigEgg.java
// An inner class cannot be overriden like a method.
import static net.mindview.util.Print.*;
class Egg {
private Yolk y;
protected class Yolk {
public Yolk() { print("Egg.Yolk()"); }
}
public Egg() {
print("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg {
public class Yolk {
public Yolk() { print("BigEgg.Yolk()"); }
}
public static void main(String[] args) {
new BigEgg();
}
} /* Output:
New Egg()
Egg.Yolk()
*///:~
此处 按理来说 new BigEgg()时 内部使用的 Yolk应该是 重载后的Yolk,但是实际上确不是。因为,BigEgg的yolk没有像 之前例子中 明确继承 Egg的Yolk。因此两个Yolk 是相互独立的,不会相互干扰。