Java编程思想: 多态

再论向上转型

因为继承的存在, 咱们能够将子类的对象引用当作基类的一个对象, 即将子类对象向上转型为基类对象.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();
  }
}
相关文章
相关标签/搜索