Java中多态梳理以及代码示例

1、什么是多态

所谓多态,就是指一个引用(类型)在不同的情况下的多种状态。也可以理解为,多态是指通过指向父类的指针,来调用在不同子类中实现的方法。

详细来说,就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

2、多态作用

提高了代码的扩展性和灵活性,前期定义的代码可以使用后期的内容。

 

3、实现多态的前提条件

(1)有继承关系

(2)子类重写父类方法

(3) 父类的引用指向其子类的对象或者接口的引用指向了实现此接口的类的对象

 

4、多态分类

(1)编译时多态,即方法的重载,调用方法是不用区分参数类型,程序会自动执行相应方法,如: 加法运算,可以使int相加,可以是double相加,都是同一个方法名,这是一种静态分派。

(2)运行时多态,即方法的重写,也就是动态绑定,使用父类引用指向子类对象,在调用某一父类中的方法时,不同子类会表现出不同结果。 这样的作用就是扩展性极好,玩过网游的话应该知道 游戏中有不同的角色,它们都有一个父类,它们做相同动作时表现出来的效果就会不一样,比如跑,魔法师的跑跟战士的跑就不会一样,这就是因为两者都覆盖了父类中的跑方法,但是各自有自己单独的实现,从而表现出多态。 如果有一天你想再加个角色,只用再写一个类继承该父类,覆盖其中的跑方法就行了,其他代码不用怎么改,所以可维护性也很好。这是一种动态分派(dynamic dispatch)

5、实现方式:继承和接口(主要是针对于运行时多态来讨论的

(1)基于继承实现的多态:

      基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。比如上面提到的游戏中的不同角色相同行为表现出来的不同效果,就是因为有一个父类角色,然后这个父类角色有多个不同的子类角色,每个子类角色对父类中的同一个方法进行了不同的重写,从而实现了不同的表现形式和效果。

(2)基于接口实现的多态

      继承是通过重写父类的同一方法的几个不同子类来体现的,而接口实现的多态是通过几不同的类实现同一个接口并覆盖接口中同一方法来体现的。在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例对象(也即接口变量必须指向实现了该接口的类的实例对象),在运行时,根据对象引用的实际类型来执行对应的方法。继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。

6、小案例:

(1)关于继承的多态

说明:定义三个类,父类Teacher,两个子类MathTeacher和EnglistTeacher,子类重写了父类中的teach方法。主类中定义了一个方法,方法参数是父类型,方法中调用了三个类都有的teach方法。这样的话,在调用方法的时候,就可以根据传入的参数类型不同,调用不同的teach实现。如果调用传入的是MathTeacher类型对象,打印I am a math teacher;如果传入的是EnglishTeacher类型对象 ,打印出I am an English teacher;如果调用传入的是Teacher对象,打印I am a teacher。这就是继承实现的多态。

public class Teacher {
    public void teach(){
        System.out.println("I am a techer");
    }
}
public class MathTeacher extends Teacher {
    public void teach(){
        System.out.println("I am a math teacher");
    }
}
public class EnglishTeacher extends  Teacher{
    public void teach(){
        System.out.println("I am an English teacher");
    }
}

b、主类:

public class Main{
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teach(teacher);

        MathTeacher mathTeacher = new MathTeacher();
        teach(mathTeacher);

        EnglishTeacher englishTeacher = new EnglishTeacher();
        teach(englishTeacher);
    }

    // 注意:此处函数中的参数类型使用时父类Teahcer。
    // 所以,传入不同的类型时,会执行不同的teach方法,打印不同的数据
    static void teach(Teacher teacher){
        teacher.teach();
    }
}

c、打印结果

I am a techer
I am a math teacher
I am an English teacher

 

(2)关于接口的多态

a、说明:关于接口的多态,在敲代码的时候经常会用到,比如使用list时,经常会这样定义:

List<Integer> list1 = new LinkedList<>();
List<Integer> list2 = new ArrayList<>();

List是接口,LinkedList和ArrayList是实现了List接口的具体类。不能定义接口类型的对象,但是可以定义接口类型变量,而且接口类型的变量必须指向实现了接口的类的对象。在调用方法的时候,就根据不同的接口变量指向的不同的类的对象,来调用不同的方法实现过程。

b、下面代码中,一个接口Travel,两个实现类TravelByCar和TravelByTrain,接口仅仅声明了方法go,类中对go方法进行了不同的实现。主类中定义了travel方法,方法参数是接口类型Travel,这样在调用方法的时候,就会根据传入的实现类的不同而调用不同的go方法

c、

public interface Travel {
    public void go();
}
public class TravelByCar implements Travel {
    @Override
    public void go() {
        System.out.println("Travel by car");
    }
}
public class TravelByTrain implements Travel {
    @Override
    public void go() {
        System.out.println("Travel by train");
    }
}

主类:

public class Main{
    public static void main(String[] args) {
        TravelByCar travelByCar = new TravelByCar();
        travel(travelByCar);

        TravelByTrain travelByTrain = new TravelByTrain();
        travel(travelByTrain);
    }

    // 注意:此处函数中的参数类型使用接口类型Travel。
    // 所以,传入不同的类型时,会执行不同的go方法,打印不同的数据
    static void travel(Travel travel){
        travel.go();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值