Java学习-8.多态

本文详细探讨了Java中的多态特性,包括向上转型、方法调用绑定、构造器与多态的交互,以及多态带来的优势和限制。通过实例分析了如何利用多态实现代码的可扩展性和灵活性,同时指出在处理私有方法和静态方法时应注意的问题。
摘要由CSDN通过智能技术生成

多态

多态方法调用允许一种类型表现出与其他相似类型之间的区别,只要它们都是从同一基类导出而来的。

再论向上转型

对象既可以作为它自己本身的类型使用,也可以作为它的基类型使用,这种把某个对象的引用视为对其基类型的引用的做法被称为向上转型(因为在继承树的画法中,积累是放在上方的)。

  //Note.java
   public enum Note {
       MIDDLE_C,C_SHAPE,B_FLAT;
   }
  //:Instrument.java
  class Instrument {
      public void play(Note n) {
         System.out.println("Instrument.play()");
      }
   }
  //:Wind.java
  public class Wind extends Instrument {
     public void play(Note n){
       System.out.println("Wind.play()"+n);
     }
  }
  //Music.java
  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);
    }
  }

Music.tune()方法接受一个Instrument引用,同时也接受任何导出自Instrument的类。

转机

方法调用绑定

将一个方法调用同一个方法主体关联起来被称作绑定。

当编译器只有一个Instrument引用时,它无法知道究竟调用哪个方法才对,解决的方法就是后期绑定,其含义是在运行时根据对象的类型进行绑定

后期绑定也称动态绑定运行时绑定
后期绑定会自动进行

产生正确的行为

向上转型还可以像下面这条语句这么简单:(Circle类由Shape类导出)

Shape s= new Circle();

这里创建了一个Circle对象,并把得到的引用立即赋值给Shape(通过继承,Circle就是一种Shape)

假设调用一个基类:

s.draw();

由于后期绑定(多态),正确调用了Circle.draw()方法。

可扩展性

根据前面的Instrument(乐器)示例:

由于有多态机制,我们可以根据自己的需要对系统添加任意多的新类型,而不需要更改tune()方法。

class Instrument {
  void play(Note n) {
    System.out.println("Instrument.play() " +n);
  }
  String what(){return "Instrument";}
  void adjust() {
    System.out.println("Adjusting Instrument");
  }
}
class Wind extends Instrument {
  void play(Note n) {
    System.out.println("Wind.play() " +n);
  }
  String what(){return "Wind";}
  void adjust() {
        System.out.println("Adjusting Wind");
  }
}
class Percussion extends Instrument {
  void play(Note n) {
    System.out.println("Percussion.play() "+n);
  }
  String what(){return "Percussion";}
  void adjust() {
    System.out.println("Adjusting Percussion");
  }
}
class  Stringed extends Instrument{
  void play(Note n) {
    System.out.println("Stringed.play() "+n);
  }
  String what(){return "Stringed";}
  void adjust(){
    System.out.println("Adjusting Stringed");
  }
}
class Brass extends Wind{
  void play(Note n){
    System.out.println("Brass.play() "+n);
  }
  void adjust(){
        System.out.println("Adjusting Brass");
  }
}
class Woodwind extends Wind{
  void play(Note n){
    System.out.println("Woodwind.play() "+n);
  }
  void adjust(){
    System.out.println("Adjusting Woodwind");
  }
}
public class Music2 {
  public static void tune(Instrument i){
    i.play(Note.MIDDLE_C);
  }
  public static void tuneAll(Instrument[] e) {
    for(Instrument i:e)
        tune(i);
  } 
  public static void main(String[] args){
    Instrument[] orchestra={
            new Wind(),
            new Percussion(),
            new Stringed(),
            new Brass(),
            new Woodwind()
    };
    tuneAll(orchestra);
  }
}

在main()中,当我们将某种引用置入orchestra数组中,就会自动向上转型到Instrument。

缺陷:覆盖私有方法

只有非private方法才可以覆盖(在导出类中,对于基类中的private方法,最好采用不同的名字)

缺陷:域与静态方法

如果某个方法是静态的,它的行为就不具有多态性

构造器和多态

构造器不具有多态性(实际上是static方法,只不过该static声明是隐式的)

构造器的调用顺序

1.调用基类构造器。这个步骤会不断地反复递归下去,首先是构造这种层次的根,然后是下一层的导出类,直到最底层的导出类。

2.按声明顺序调用成员的初始化方法。

3.调用导出类构造器的主体。

协变返回类型

表示在导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型

参考书《Java编程思想》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值