因为继承的存在, 咱们能够将子类的对象引用当作基类的一个对象, 即将子类对象向上转型为基类对象.java
class A { public void show() { System.out.println("A show()"); } } class B extends A{ public void show() { System.out.println("B show()"); } } public class C { public static void func(A a) { a.show(); } public static void main(String[] args) { B b = new B(); // B show() func(b); } }
绑定ide
将一个方法调用同一个方法主体关联起来被称做绑定, 在程序执行前进行绑定称为前期绑定.函数
当咱们编写上例中的代码:this
public static void func(Cycle c) { c.ride(); }
咱们如何肯定方法ride所对应的对象c是什么类型?spa
这就引起了动态绑定的概念. 即在静态编译阶段, 咱们实际上并不知道c的类型是什么. 只有等到运行阶段, 咱们经过某种方法, 得到此方法的类签名, 才能正确的调用此方法.code
覆盖引起动态绑定对象
考虑上例中: 只有子类覆盖了基类的方法, 才会引起多态. 在动态运行阶段, a.show()被执行时候, 其方法签名若为B对象, 则它事先查看A中是否有show方法, 若是有则进行向下转型, 使用实际的B对象调用show.继承
若是使用private/final阻止多态的产生, 那程序则一般不会按咱们预期的进行执行:递归
class A { private void f() { System.out.println("A f()"); } public static void main(String[] args) { A a = new B(); // A f() a.f(); } } public class B extends A{ // @Override public void f() { System.out.println("B f()"); } }
若是咱们要强制执行多态, 则最好使用@Override进行强制覆盖.编译
构造器的调用顺序
构造器的调用顺序必然是先调用基类构造器, 而后递归下去调用子类构造器.
构造器的主要任务是: 检查对象是否被正确构造. 因此只有父类构造器正确的调用, 才可确保子类的构造器正确的调用.
继承与清理
在继承状况下, 若是须要手动编写清理函数, 那么子类的清理函数必须调用父类的清理函数.
对象的销毁顺序应该和初始化顺序相反. 考虑顺序定义两个对象A,B, 那么在B中是能够引用对象A的. 正确的销毁步骤是调用B的清理函数, 而后在调用A的清理函数.
若是是先调用A的清理函数, 那么在调用B的任何函数时(包括销毁函数), 在B中的A对象是无效的, 则致使异常的发生.
class A { public void dispose() { System.out.println("A dispose"); } } public class B extends A{ private A a = new A(); public void dispose() { System.out.println("B dispose."); a.dispose(); super.dispose(); } public static void main(String[] args) { B b = new B(); b.dispose(); } }
存在一种特殊的状况, 即一个对象被多个对象所共享. 那么须要经过计数来判断何时须要清理对象:
class Shared { private int refcount = 0; private static long counter = 0; private final long id = counter++; public Shared() { System.out.println("Creating " + this); } public void addRef() { refcount++; } public 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 "Composing " + id; } } public class ReferenceCounting { public static void main(String[] args) { 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(); } } }
构造器内部的多态方法的行为
假设class A extends B, 那么在A中使用super来引用B. 但super的类型其实是A的, 它向上转型为B, 经过强制类型转换(B) super.
这能够解释构造器中的多态行为:
class A { A() { System.out.println("A constructor."); show(); } public void show() { System.out.println("A show"); } } public class B extends A{ B() { System.out.println("B constructor."); } public void show() { System.out.println("B show"); } public static void main(String[] args) { // A constructor. // B show // B constructor. B b = new B(); } }