第8章 多态

  • 最近编程时候,遇见了一个问题,当时怎么都想不通。最后,谁知是多态。所以要静心研究下多态。

多态的定义

  • 多态一般分为两种:
    • 编译时的多态:
      • 方法的重载
    • 运行时的多态:
      • 继承
      • 实现接口
  • 我们所说的多态一般是运行时的多态。
  • 要使用多态,在声明对象时就应该遵循一条法则:声明的总是父类类型或接口类型,创建的是实际类型。
  • 面向对象的三大特征: 封装 继承 多态
  • 多态通过分离 做什么 和 怎么做 ,从另外的一个角度将接口和实现分离开来。
  • 封装通过合并特征和行为来创建新的数据类型。“实现隐藏”则是通过将细节“私有化”把接口和实现分离开。
  • 多态的作用是消除类型之间的耦合关系。
  • 多态也叫作动态绑定,后期绑定,运行时绑定。
  • 首先是一个多态的例子:
class Instrument {
  public void play(Note n) {
    print("Instrument.play()");
  }
}

public class Wind extends Instrument {
  public void play(Note n) {
    System.out.println("Wind.play() " + n);
  }
}

public class Music {
  public static void tune(Instrument i) {
    i.play(Note.MIDDLE_C);
  }
  public static void main(String[] args) {
    Wind flute = new Wind();
    tune(flute); // Upcasting
  }
}
// Output:
//Wind.play() MIDDLE_C

方法调用绑定

  • 将一个方法同一个方法主体关联起来叫做 绑定。如果程序执行前进行绑定的话,叫做前期绑定。(这一般是面向过程语言的绑定过程)

  • 后期绑定:运行时根据对象的类型进行绑定。

  • 后期绑定在不同的语言中事先有所不同,但是想象一下就会得知,不知怎样必须在对象中安置某种类型信息。
  • java中出了 finalstatic 方法之外,所有的方法都是后期绑定。
  • 声明为final方法的好处:防止其他人覆盖该方法。但是更重要的一点是:这样做可以有效地关闭动态绑定。

多态的“缺陷”

  • private方法被自动的认为是final方法,对于导出类是屏蔽的。
public class PrivateOverride {
  private void f() { print("private 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()
  • 只有普通的方法调用可以是多态的。域(变量)和静态的方法也不具有多态性质。
class Super {
  public int field = 0;
  public int getField() { return field; }
}

class Sub extends Super {
  public int field = 1;
  public int getField() { return field; }
  public int getSuperField() { return super.field; }
}

public class FieldAccess {
  public static void main(String[] args) {
    Super sup = new Sub(); // Upcast
    System.out.println("sup.field = " + sup.field +
      ", sup.getField() = " + sup.getField());
    Sub sub = new Sub();
    System.out.println("sub.field = " +
      sub.field + ", sub.getField() = " +
      sub.getField() +
      ", sub.getSuperField() = " +
      sub.getSuperField());
  }
} /* Output:
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0
*///:~

构造器和多态

  • 对于导出类的构造器,在第一行必须调用 基类 的构造器,否则编译器会报错。当然,如果基类有无参的构造器,则可以不用显式的调用,因为编译器会帮助我们隐式调用。
    • 首先将分配给对象的空间初始化为二进制的0
    • 按声明顺序调用成员的初始化方法
    • 然后调用该类的构造器
  • 根据以上规则,当我们手动写dispose()方法的时候,我们销毁的顺序应该是和初始化的顺序是相反的,因为这样可以避免某个子类对象依赖其他的对象。
  • 如果遇到类之间有共享变量的情况,那么销毁的顺序就变得复杂了,一般采用计数器的方法,记录着引用的个数。
  • 在构造器内唯一安全调用的那些方法是final方法,也适用于private方法,因为他们自动属于final方法。

协变返回类型

  • 协变返回类型就是如果方法要求返回一个对象,则我们可以返回这个对象的子类。

向下转型

  • 向上转型我们会丢失具体的类型信息
  • 在java中,所有的转型都会得到检查。这种运行期间对类型进行检查的行为称作“运行时的类型识别”。

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值