Skip to content

多态(polymethod)


问题引入

多态是建立在封装和继承基础之上的

为什么需要多态?

代码的复用性不高,不利于维护

举例

人给动物喂食这个方法,如果动物类别添加了,那食物类别也需要添加,那必然会造成需要不断地添加方法,就会造成代码的复用性不高

方法体现多态

(1)同类中方法的重载和继承关系中方法的重写体现多态

(2)虽然都是同一个方法,但是可以以一定的规则调用不同的方法,提高了代码的复用性

对象体现多态

(1) 一个对象的编译类型运行类型可以不一致

(2) 编译类型在定义对象时,就确定了,不能改变

(3) 运行类型可以变化

(4) 编译类型看定义时 = 号的左边运行类型看 = 号的右边

总结:多态的体现就在于父类的引用(编译类型)可以接收(指向)子类的对象(运行类型),这样的好处在于方便统一管理,无需重复编写代码

向上转型

(1)语法:父类类型 引用名 = new 子类类型 ( ) ;

(2)特点:编译类型看左边,运行类型看右边

(3)可以调用父类中的所有成员(需要遵守访问权限限制),不能调用子类特有的成员(能够调用哪些内容是由编译类型决定的)

(4)最终运行效果看子类的具体实现

因为子类在等号右边,运行结果看运行类型

向下转型

(1)语法:子类类型 引用名 = (子类类型) 父类引用;

(2)只能强转父类的引用不能强转父类的对象

(3)要求父类的引用必须指向的是当前目标类型的对象

(4)当向下转型后,可以调用子类类型中所有的成员

补充:调用的时候优先在本类中找,如果没有就找到父类,直到 Object

代码示例

java
// 父类
package poly;

public class animal {
    public void run(){
        System.out.println("调用animal类中的---run()方法");
    }
    public void eat(){
        System.out.println("调用animal类中的---eat()方法");
    }
    public void show(){
        System.out.println("调用animal类中的---show()方法");
    }
    public void get(){
        System.out.println("调用animal类中的---get()方法");
    }
}

// 子类
package poly;

public class cat extends animal{
    public void run(){
        System.out.println("调用cat类中的---run()方法");
    }
    public void eat(){
        System.out.println("调用cat类中的---eat()方法");
    }
    public void show(){
        System.out.println("调用cat类中的---show()方法");
    }
    public void print(){
        System.out.println("调用cat类中的---print()方法");
    }
}

// 主类
package poly;

public class main {
    public static void main(String[] args) {

        /*
                                 说明
            (1)父类和子类都有run(),eat(),show()方法
            (2)父类独有get()方法,子类没有
            (3)子类独有print()方法,父类没有
         */

        //一、向上转型(可以调用父类的所有成员,但是不能调用子类的)
        animal animal = new cat(); // 使用父类的引用接收子类的对象


        animal.eat();  // 运行结果看子类,运行类型是cat,优先调用cat中的eat()方法
        animal.run();
        animal.show();

        animal.get(); // 运行类型是子类cat,但是没有get()方法,于是找到父类中get()方法调用

//        animal.print();  // 错误,无法调用子类


        //二、向下转型(可以调用子类的所有成员)
        cat cat = (cat)animal;  // 原先用animal指向cat对象的堆空间,强转之后使用cat引用指向
        cat.print();
    }
}

//运行结果
调用cat类中的---eat()方法
调用cat类中的---run()方法
调用cat类中的---show()方法
调用animal类中的---get()方法
调用cat类中的---print()方法

使用细节

1. 多态前提是:类之间存在继承关系

2. Java 中,子类引用不可以指向父类,但是父类引用可以指向子类,这是由于继承关系的特性

3. 父类引用指向子类对象

(1)父类引用可以指向子类对象,因为子类是父类的扩展(除了拥有父类的内容以外,子类可以拥有自己的内容,但是父类不会拥有),子类对象是父类类型的一个实例。

(2)这时,父类引用只能访问父类中的方法和属性,不能访问子类特有的方法和属性(除非进行类型转换)。

4. 子类引用不能指向父类对象

(1)子类是父类的扩展,子类中可能有父类没有的属性和方法,编译器无法保证子类引用指向父类对象时访问的安全性。

(2)如果强行让子类引用指向父类对象,编译器会报错,除非进行强制类型转换并且确保类型安全(通过 instanceof 检查等方式)