- 8.2 转机
- 绑定:将一个方法调用通一个方法主体(方法所在的类)关联起来。
- 在程序执行前进行绑定叫做前期绑定;在运行时根据对象的类型进行绑定叫做后期绑定(动态绑定or运行时绑定)。后期绑定机制随着语言的不同有着差异,但是都必须在对象中安置某种“类型信息”。
- Java中除了static方法和final方法(private方法属于final方法)之外,其他都是后期绑定。(用final的一个优势或许是有效的“关闭”动态绑定)
- 动态绑定步骤:JVM提取对象实际类型的方法表->JVM搜索符合参数要求的方法->调用方法
- 只有普通方法调用是多态的(后期绑定),直接访问某个域(a data memeber of a class),这个访问是在编译期进行解析的。
public class PrivateOverride{ private void f(){ print("pirvate f()"); } public static void main(String[] args){ PrivateOverride po = new Derived(): po.f(); } } class Derived extends PrivateOverride{ public void f(){ print("public f()"); } } //output: private f() //private方法根本无法覆盖 ``` ``` class Super{ public int field = 0; //... } class Sub extends Super{ public int field = 1; //... } /... Super sub = new Sup(); System.out.println(sup.field) /... //output: 0
- 8.3 构造器和多态
- 确保导出类所要使用的成员都已经构建完毕(基类中可能有private类型,只有基类自己可以调用private成员变量),必须要先调用基类的构造器。
- 销毁的顺序应该和初始化顺序相反,首先对导出类进行清理,然后才是基类。
- 如果存在多个对象共享的情况,就要使用引用计数来跟踪。(附代码)
- 如果在构造器内部调用一个动态绑定的方法,就要用到那个方法的被覆盖后的定义。在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。这个就是导致代码中r=0的原因(附代码)
- 用尽可能简单的方法使对象进入正常状态,如果可以的话避免条用其他方法。(可以调用private或者final方法)
- 协变返回类型:表示在导出类中的被覆盖方法可以返回基类方法返回类型的某种导出类型。(附代码)
class Shared { private int refcount = 0; private static long counter = 0;//static共用一个空间,表示实例的数量 private final long id = counter++; //final表示不希望其在声明周期有所变化 public Shared() { System.out.println("Creating " + this); } public void addRef() { refcount++; } protected void dispose() { if (--refcount == 0) { System.out.println("Disposing " + this); } } public String toString() { return "Shared " + id; } } class Composing { private Shared shared; private static long counter = 0; private final long id = counter++; public Composing(Shared shared) { System.out.println("Creating " + this); this.shared = shared; this.shared.addRef(); } protected void dispose() { System.out.println("disposing " + this); shared.dispose(); } public String toString() { return "Compsing " + id; } } public class test { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Shared shared = new Shared(); Composing[] composing = { new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared) }; for (Composing c : composing) { c.dispose(); } } }
输出:
Creating Shared 0 Creating Compsing 0 Creating Compsing 1 Creating Compsing 2 Creating Compsing 3 Creating Compsing 4 disposing Compsing 0 disposing Compsing 1 disposing Compsing 2 disposing Compsing 3 disposing Compsing 4 Disposing Shared 0
class Super{ void draw(){ out.println("super draw"); } Super(){ out.println("before draw"); draw(); out.println("after draw"); } } class Sub extends Super{ private int r = 1; Sub(int i){ r = i; out.println("sub constructor" + " " + r); } void draw(){ out.println("sub draw" + " " + r); } } public class test { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub new Sub(5); } }
输出:
before draw sub draw 0 after draw sub constructor 5
协变返回类型:
class Super1{ } class Sub1 extends Super1{ } class Super2{ Super1 process(){ return new Super1(); } } class Sub2{ Sub1 process(){ return new Sub1(); } }
- 8.5 用继承进行设计
- 向下转型:基类转成导出类。在运行期间对类型进行检查的行为成为“运行时类型识别”(RTTI)。
//Draw是Art的一个子类,里面有一个增加的paly3()方法 Art[] arts = { new Art(), new Draw(5) }; ((Draw)arts[0]).play3();//Exception thrown ((Draw)arts[1]).play3();//Downcast
相关文章