多态:面向对象三大特征之一

面向对象三大特征:封装、继承、多态

封装:面向对象三大特征之一 - 鹿先森JIAN - 博客园 (cnblogs.com)

继承:面向对象三大特性之一 - 鹿先森JIAN - 博客园 (cnblogs.com)

多态概述:

  多态(Polymorphism)的前提是封装形成独立体,独立体之间存在继承关系,从而产生多态机制。

  多态就是“同一个行为”发生在 “不同的对象上” 会产生不同的效果。 

java 中允许这样的两种语法出现:

  向上转型(Upcasting),是指子类型转换为父类型,又被称为自动类型转换

  向下转型(Downcasting),是指父类型转换为子类型,又被称为强制类型转换。

多态的语法:

  达到多态三个必要条件:1.继承  2.方法重写   3.向上转型(自动类型转换)

  特点:多态形式,只能调用重写的方法,执行的是子类的方法;不能调用子类独有的方法!

public class Animal {
    public void eat(){
        System.out.println("Animal.eat...");
    }
}
//----------------------
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("Cat.eat...");
    }
    void catchMouse(){
        System.out.println("猫抓老鼠。。。");
    }
}
//------------------------
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Dog.eat...");
    }
    void lookDoor(){
        System.out.println("狗看门。。。");
    }
}
//-------------------------
public class Test {
    public static void main(String[] args) {
     Animal a1 = new Cat(); Animal a2
= new Dog();  //向上转型(自动) a1.eat();
     a2.eat();
} }
执行结果:
  Cat.eat... 
  Dog.eat... 

我们现在让多态创建出来的猫对象,去抓老鼠

 

编译报错,因为 catchMouse()方法属于子类Cat 中独有的行为,如果想要调用抓老鼠的方法,我们可以将对象向下转型为猫对象

既然这样,能将 Cat类转为 Dog类,然后调用Dog类特有的lookDoor()方法吗?

运行报错:ClassCastException,翻译为类型转换异常

因为 a1引用指向的对象是一只 Cat,然后我们要将一只Cat强制转换成一只 Dog,这显然是不合理的,因为 Cat和 Dog之间是没有继承关系的。为了避免这种异常的发生,建议在进行向下转型之前进行运行期类型判断,这就需要我们学习一个运算符了,它就是 instanceof 关键字

下面代码中:a1 instanceof Dog,翻译为:a1引用的对象,是不是 Dog类型True 或 False

执行结果:类型不匹配 

 ------------------------------------------------------------------------------------

package test;
//饲养员类
public class AnimalKeeper {
    private String name;
    //提供getter和setter方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //无参构造
    public AnimalKeeper() {}
    有参构造
    public AnimalKeeper(String name) {
        this.name = name;
    }
//    public void feed(Cat cat){
//        System.out.println(name+"喂猫");
//    }
//    public void feed(Dog dog){
//        System.out.println(name+"喂狗");
//    }

    public void feed(Animal animal){    //类作为参数类型
        System.out.println(this.name+"在喂动物");
        animal.eat();
    }
}
//---------------------------
package test;
public class Test {
    public static void main(String[] args) {
        Cat c1 = new Cat();
        Dog d1 = new Dog();
        AnimalKeeper a1 = new AnimalKeeper("小明");
        a1.feed(c1);
     a1.feed(d1); } }
执行结果:
  小明在喂动物
  Cat.eat...
  Dog.eat...

在以上程序中,AnimalKeeper 类中的方法feed(Animal animal) 的参数类型定义为更加抽象的Animal 类型,而不是feed(Dog dog) 或 feed(Cat cat),显然AnimalKeeper 类和具体的Dog、Cat 类解耦合了,依赖性弱了,这就是我们通常所说的面向抽象编程,尽量不要面向具体编程,面向抽象编程会让你的代码耦合度降低,扩展能力增强。如果想新增一个 Bird类,只需在Test 类里:Bird b =new Bird(); a1.feed(b); 就可以了,多方便,也不用再 AnimalKeeper类写了。

posted @ 2022-03-21 19:54  鹿先森JIAN  阅读(33)  评论(0编辑  收藏  举报