黑马程序员_基础复习05_多态

  ------- android培训java培训、期待与您交流! ---------- 

多态:事物之间存在多种体现形态

1、多态的体现

   父类引用指向子类对象,父类引用也可以接受自己的子类对象。这么做的好处是提高了程序的扩展性,但是使用多态的前提是存在继承或实现。

下面的代码是父类引用接收子类对象:

class Cycle{

   private String name;

   public Cycle(){

   }

   public String toString(){

     return name + "  ";

   }

}

class Unicycle extends Cycle{

  private String name;

  public Unicycle(String name){

    this.name = name;

  }

  public String toString(){

    return name + "  ";

  }

}

class Bicycle extends Cycle{

  private String name;

  public Bicycle(String name){

    this.name = name;

  }

  public String toString(){

    return name + "  ";

  }

}

class Tricycle extends Cycle{

  private String name;

  public Tricycle(String name){

    this.name = name;

  }

  public String toString(){

    return name + "  ";

  }

}

public class DuoTai {

   public static void ride(Cycle c){

     System.out.println(c.toString() + "riding");

   } 

   public static void main(String[] args){

     Unicycle u = new Unicycle("unicycle");

     Bicycle b = new Bicycle("bicycle");

     Tricycle t =  new Tricycle("tricycle");

     ride(u);

     ride(b);

     ride(t);

   }

} 

这样做的好处是,如果以后要继承出新的Cycle子类,我们不需要重载ride()方法,省去了大量不必要的工作。

2、动态绑定

 动态绑定又叫做运行时绑定,就是在运行时根据对象的类型进行绑定。在编译时期,编译器不知道对象类型,但方法调用机制能够找到正确的方法体。

Java中除了staticfinal方法之外,都是动态绑定。

3、多态中成员函数的特点:

 1) 对于非静态的成员函数,在编译期间,参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,没有则编译失败。运行期间,参阅对象所属的类中是否有调用的方法。

即编译看左边,运行看右边。

 2)对于静态的成员函数,无论编译还是运行,都参考左边。

 3)对于成员变量,无论是静态还是非静态,都参考左边。

class Rodent{

  public void eat(){

    System.out.println("Rodent.eat()");

    drink();

  }

  public void drink(){

    System.out.println("Rodent.drink()");

  }

}

class Mouse extends Rodent{

  public void drink(){

    System.out.println("Mouse.drink()");

  }

}

public class DuotaiTest {

  public static void main(String[] args){

    Rodent m = new Mouse();

    m.eat();

  }

}

 因为多态中 Rodent m = new Mouse();父类指向了子类对象,也就是说将子类对象提升为了父类对象。
 m.eat(); 提升为父类对象后,调用eat()方法。因为父类中也定义了eat()方法,所以编译通过,如果父类中没有定义该方法,就会编译失败。即所谓的编译看左边,左边即父类。
 因为m被提升为父类对象,m.eat()也是调用父类中的方法,但是为什么输出的是Mouse.drink()而不是Rodent.drink()
原因很简单,因为子类中也定义了同名的drink()方法,发生了函数的覆盖,子类覆盖了父类中的同名函数,所以运行的是子类的函数,也就是所说的运行看右边,因为右边是子类。

;