实例通俗理解Java中的多态

实例通俗理解Java中的多态

多态定义

不同类的对象(有共同的父类)面对同一消息(消息可对应理解为方法)做出不同的响应。看一个简单的例子:

定义父类:Peson.java,方法:eatdinner

public class Person {
    public Person(){}
    public void eatdinner(){
        System.out.println("a person is eatting dinner");
    }
}

定义子类:Student.java,方法:eatdinner,继承自Person并重写了父类方法

public class Student extends Person{
    public Student(){}
    @Override
    public void eatdinner() {
        System.out.println("a student is eatting dinner");
    }
}

定义子类:teacher.java,方法:eatdinner,继承自Person并重写了父类方法

public class Teacher extends Person {
    public Teacher(){}
    @Override
    public void eatdinner() {
        System.out.println("a teacher is eatting dinner");
    }
}

测试多态效果:test.java,注意看注释

public class test {
    public static void  main(String[] args){
        Person Pstudent = new Student();//Java中的向上转型:父类(Person类)引用指向子类实例对象(Student对象)
        Person Pteacher = new Teacher();//Java中的向上转型:父类(Person类)引用指向子类实例对象(Teacher对象)
        Pstudent.eatdinner();
        Pteacher.eatdinner();//不同对象面对同一消息(函数)做出的不同反应,注意看以下运行结果
    }
}

不清楚对象之间的向上转型和向下转型的区别请戳这里,另附上基本数据类型的转型

运行结果:

a student is eatting dinner

a teacher is eatting dinner

可以看出不同对象面对同一消息(函数)做出的不同反应,注意看以上运行结果。

总结多态存在的三个必要条件

  • 继承

    Teacher和Student均继承了父类Person

  • 重写

    Teacher和Student均重写了Person类中的eatdineer

  • 向上转型

    父类引用指向子类实例对象

多态的作用

解耦合,消除类与类之间的关系,结合场景理解:比如面对一个类中有一些功能类似的方法,像实现一个人打球的方法,如果一个人会打乒乓球,篮球,羽毛球,如果不用多态,实现如下:

  • 非多态版本:

既然是打球,首先得有个球吧,那定义三个球类吧,篮球乒乓球羽毛球三个类,球有什么方法,那只有被打了,并实现方法played

定义Basketball.java

public class Basketball {
    public void played(){
        System.out.println("打会儿篮球");
    }
}

定义Badminton.java

//羽毛球
public class Badminton {
    public void played(){
        System.out.println("打会儿羽毛球");
    }
}

定义Tabletennis

public class Tabletennis {
    public void played(){
        System.out.println("打会儿乒乓球");
    }
}

打球得人来打吧,那再定义个person类

person.java

public class person {
    //重载实现打三种球
    public void playball(Basketball basketball){
        basketball.played();
    }
    public void playball(Tabletennis tabletennis){
        tabletennis.played();
    }
    public void playball(Badminton badminton) {
        badminton.played();
    }
}

实现打球playball功能,当然是你给我传什么球person打什么球,但是每个球的类型都不一样,那怎么办?所以得重载的方法实现三个打球的方法,分别传不同的球给人,刚好完美解决这个问题。写demo测试一下:

public class demotest {
    public static void main(String[] args){
        //实例化人、篮球、羽毛球、乒乓球
        person p1 = new person();
        Basketball basketball = new Basketball();
        Badminton badminton  = new Badminton();
        Tabletennis tabletennis = new Tabletennis();
        //球传给人,开始打球
        p1.playball(basketball);
        p1.playball(badminton);
        p1.playball(tabletennis);
    }
}

输出结果如下,可以看出实现了这三种功能:

打会儿篮球

打会儿羽毛球

打会儿乒乓球

那么问题来了,如果现在又学会了足球呢?除了实现一个足球的类之外,还得在person类里加一个打足球playball方法,person类修改如下:

public class person {
    public void playball(Basketball basketball){
        basketball.played();
    }
    public void playball(Tabletennis tabletennis){
        tabletennis.played();
    }
    public void playball(Badminton badminton) {
        badminton.played();
    }
    public void playball(Football football) {
        football.played();
    }
}

以后再添加一种球,就得修改一下person,十分麻烦,有没有一种方法不用修改person类,对于这种打球的功能,实现一个统一的方法,当你传入不同的球,能让person自己打不同的球。这不就是多态吗?不同类的对象(各种球)面对同一消息(打球的函数)做出不同的响应(实现打不同的球)。那来写一下吧。首先实现所有球的父类Ball.java

  • 多态版本
public class Ball {
    public void played(){
        System.out.println("打会儿球吧");
    }
}

然后分别实现篮球、羽毛球、乒乓球类,都继承了Ball类

public class Basketball extends Ball {
    @Override
    public void played(){
        System.out.println("打会儿篮球");
    }
}
public class Badminton extends Ball{
    @Override
    public void played(){
        System.out.println("打会儿羽毛球");
    }
}
public class Tabletennis extends Ball {
    @Override
    public void played(){
        System.out.println("打会儿乒乓球");
    }
}

实现person类:

public class person {
    public void playball(Ball ball){
        ball.played();
    }
}

测试:

public class demotest1 {    
    public static void main(String[] args){
        person p1 = new person();
        Ball basketball = new Basketball();//父类(ball)引用指向子类实例(basketball)
        Ball badminton  = new Badminton();
        Ball tabletennis = new Tabletennis();
        p1.playball(basketball);
        p1.playball(badminton);
        p1.playball(tabletennis);
    }
}

结果:

打会儿篮球

打会儿羽毛球

打会儿乒乓球

如果此刻再来了一个足球或者其他什么球,也没有关系,只要让其继承了Ball父类,然后重写了父类中的方法就可以作为参数传入到person类中的playball方法中,在实际操作中,Ball父类更多采用的接口而不是类,因为其中定义的方法并没有用到,都是调用子类中重写的方法。

多态注意点

三个条件:继承;重写;向上转型。

向上转型后,父类引用------>子类实例,方法和变量的该调用父类还是子类需要注意,和普通的继承关系不一样,具体总结如下:

类型调用方式
同名静态方法调用父类的
同名成员方法调用子类的
同名静态成员调用父类的
同名成员成员调用父类的

多态应用场景

个人理解,很多向上转型的场景其实都用到多态了,这里需要理解一下,首先向上转型,肯定是父类引用----->子类实例,这里其实已经有了上面提出的多态两个条件了,继承和向上转型,然后调用一个子类方法,很容易就满足了多态的条件。那么多态有哪些具体场景:

  • 用于方法的参数中

    上述的打球就是一个很好的例子

  • 用于方法的返回类型中

    接着以打球举个例子,上述的basketball、tabletennis等对象都是通过new出来的,对于这些有共同父类的对象,能不能用同一种方法来实现实例化对象,而不是直接new,在主程序中直接new,如果别人没有看过你的basketball、tabletennis等类的源码不会觉得这些球类之间有共同的父类的,个人理解,这写法都是为了方便理解。

//以前写法
public class demotest1 {
    public static void main(String[] args){
        person p1 = new person();
        Ball basketball = new Basketball();
        Ball badminton  = new Badminton();
        Ball tabletennis = new Tabletennis();
        p1.playball(basketball);
        p1.playball(badminton);
        p1.playball(tabletennis);
    }
}
//工厂类写法
public class BallFactoryTest {
    public static void main(String[] args){
        Ball ball1 = BallFactoryDemo.Ballproduce("basketball");
        Ball ball2 = BallFactoryDemo.Ballproduce("badminton");
        Ball ball3 = BallFactoryDemo.Ballproduce("tabletennis");
        person p1 = new person();
        p1.playball(ball1);
        p1.playball(ball2);
        p1.playball(ball3);
    }
}

那么BallFactoryDemo是个什么呢,不用想的很复杂,其实就是个if-else嵌套写的,代码如下:

package BallFactory;
public class BallFactoryDemo {
    //用Ball父类(方法返回类型为Ball)来接收子类实例对象(实际返回子类实例)----->多态
    public static Ball Ballproduce(String ball){
        if (ball.equals("basketball")){
            return new Basketball();
        }else if (ball.equals("badminton")){
            return new Badminton();
        }
        else if (ball.equals("tabletennis")){
            return new Tabletennis();
        }
        else{
            System.out.println("no ball");
            return null;
        }
    }
}

可以看出BallFactoryDemo类就像一个Ball工厂一样,可以生产出各种不同的Ball对象,其返回值可以是Ball的各种子类,这一点就很好的利用到了多态,使用父类引用接收了子类实例,而上面的BallFactoryDemo类实际上就是个工厂类,这就是传说中设计模式中的工厂模式,是不是不知不觉就get了工厂模式和多态知识点。


作者:@caiyu@Email:347632365@qq.com

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值