• 多态到底有什么用?


    多态到底有什么用?

    结论:多态可有可无但又至关重要,在不考虑代码今后的发展时,多态是无用的,如果考虑以后代码的修改与增删,多态是能大大提高代码的扩展性与复用的。

    想搞清楚有什么用之前,先说说什么是多态:

    多态可以理解为一个事物可以拥有多种形态(自己理解的,后面会讲为啥)

    规范定义:

    1.需要有继承或者接口的实现

    2.父类引用变量需要指向子类对象

    例:

    class A{}  
    class A1 extends A{}
    
    interface B{}
    class B1 implements B{}
    
    class Test{
        public static void main(String[] args){
            
            // 父类引用变量指向子类对象(继承例子)
            A a1 = new A1();
            
            // 接口时的多态
            B b1 = new B1();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如上便是多态,多态本身就是向上转型的结果,即父类引用变量指向子类对象。

    但很明显我们还是不知道这样子到底有什么用。此时我们来看一个简单案例:

    我有一个车库,车库中停放了几辆车:Benz(奔驰)、Bmw(宝马)以及奥迪(Audi)

    场景:我每天都会叫管家把我要开的车帮我开出车库、且开什么车随心情而定。

    这是不使用多态情况下的实现

    public class Test08 {
    
        //假如测试类就是管家、它需要定义三个方法(重载),分别去获取三辆车,这样才能在接收到指令时去获取指定的车
        public void getCar(Benz benz){
            benz.getName();
        }
        public void getCar(Bmw bmw){
            bmw.getName();
        }
        public void getCar(Audi audi){
            audi.getName();
        }
    
        // main方法代表我,我去告诉管家要开哪一辆车就是去调用哪一个方法
        public static void main(String[] args) {
    
            // 比如说我想开宝马,就new宝马对象
            Bmw bmw = new Bmw();
    
            // 生成管家
            Test08 test08 = new Test08();
    
            // 管家开出宝马
            test08.getCar(bmw);
        }
    }
    
    /*
        我有一个车库,车库中停放了几辆车:Benz(奔驰)、Bmw(宝马)以及奥迪(Audi)
        场景:我每天都会叫管家把我要开的车帮我开车车库、且开什么车随心情而定。
    
     */
    class Benz{
    
        public void getName() {
    
            System.out.println("今天开奔驰");
        }
    }
    class Bmw{
    
        public void getName() {
    
            System.out.println("今天开宝马");
        }
    }
    class Audi{
    
        public void getName() {
    
            System.out.println("今天开奥迪");
        }
    }
    
    结果:
        今天开宝马
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    可以看出,虽然管家类使用的重载,但每一个车都需要一个方法,如果又来一辆车那么又需要定义一个方法,这样无疑是繁琐且违背了面向对象的设计原则(如:开闭原则)

    那当我们使用多态:

    public class Test09 {
    
        // 依旧测试类作为管家,但是此处只需要定义一个方法
        public void getCar(Car car){
            car.getName();
        }
    
        // main作为我去动态让管家出车
        public static void main(String[] args) {
    
            // 定义出三辆车,但是用接口引用变量指向子类对象
            Car benz = new Benz();
            Car bmw = new Bmw();
            Car audi = new Audi();
    
            // 定义出管家
            Test09 test09 = new Test09();
    
            // 可以看出我们传入的参数类型都是 Car
            test09.getCar(benz);
            test09.getCar(bmw);
            test09.getCar(audi);
        }
    }
    
    // 定义一个车的接口,可以看做车库
    interface Car{
    
        // 定义一个方法,可以看做出去哪一辆车
        public void getName();
    }
    
    class Benz implements Car{
    
        public void getName() {
    
            System.out.println("今天开奔驰");
        }
    }
    class Bmw implements Car{
    
        public void getName() {
    
            System.out.println("今天开宝马");
        }
    }
    class Audi implements Car{
    
        public void getName() {
    
            System.out.println("今天开奥迪");
        }
    }
    结果:
        今天开奔驰
    	今天开宝马
    	今天开奥迪
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    1.如上代码最关键处在于main方法中调用getCar()方法时的参数、可以看到参数类型都是一样的Car但传进去之后却能根据接口类型的引用变量所指向的实现类而去动态调用定义实现类中的方法。

    2.当我们需要再添加车时,只需要将车类实现接口,且在main方法中new出实例并调用getCar方法即可、管家类中代码是不需要变动的。

    3.这里的管家类还可以有一个作用,就是 AOP 织入,我可以让管家在拿车前后做一些事,如告诉管家先洗个车加个油,如果使用多态后我们只需要在一个方法中去增加这些步骤,而不是像没使用多态时每一个方法中都需要添加。

    这样大大提高程序的复用性和扩展性

    那有没有实际运用到多态的案例呢?

    其实很多案例都用到了多态的思维,如静态代理、动态代理。原本也想摆出来讲讲,但转念一想多态不是某一个案例就能一言以蔽之的、反而讲的越多,就搞的越复杂。只观如上两个案例足矣。

    思考题

    注:请使用辩证思维看待如下回答,答主才疏学浅,误导人就不美了

    Spring 框架中为何需要在 Dao 层 ,Service 层中加一个接口,然后去实现它?不加行不行?

    回答这个问题前先讲讲加了接口有什么用。

    1.其实还和多态有关系,我加接口后,在进行bean注入时可以使用接口类型去接收。这样在接口只有一个实现类时是没有差别的,那如果接口有两个实现类呢,且第二个实现类是在第一个类基础上增加一些功能,比如:日志,事务等等。这样我们可以在不改变原有实现类的基础上横向增加(AOP)功能。

    2.如上功能还有个方便地方,如果不加接口也可以实现,就是继承原实现类,然后再取添加功能,但是这样在使用时就需要改很多地方,因为使用的类名不同了,那么代码中各处类名就需要重写,但如果是接口,只需要在注入时将接口类型的引用变量重新指向新的实现类对象即可,其余代表均无需改变。

    综上而言,无论是加与不加都能实现功能,但是要考虑后期维护或增添,加接口会远远比不加来的方便

    我们在使用集合对象时,固定喜欢使用接口类型变量去接收实现类对象,为啥要这样做,不这样行不行?

    上述问句的代码体现为:

    List<Integer> list = new ArrayList<Integer>();
    Map<String,String> map = new HashMap<String,String>();
    
    • 1
    • 2

    上述代码不好体现用处,我们再换一种写法:

        public List getList_1(){
            return new ArrayList();
        }
        public List getList_2(){
            return new ArrayList<Integer>();
        }
        public Map getMap_1(){
            return new HashMap();
        }
        public Map getMap_2(){
            return new HashMap<Integer,String>();
        }
    ======================================
        public ArrayList getList_3(){
            return new ArrayList<Integer>();
        }
        public HashMap getMap_3(){
            return new HashMap<Integer,String>();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这是六种获取集合的方法,假如按照最下面两种去写,那么获取的对象类型永远是固定的,并且使用时只能使用一种类型。那如果现在有个需求需要更换类型,从ArrayList变成Vector ,如果是最下面两种是不是除了方法,返回值要改,使用时获取此返回值的变量类型也需要改,如果此变量作为某方法的参数,那么方法参数类型是不是也要改?

    而如果是以接口类型返回的,则只需要在get方法中修改new出来的对象即可,即:

        public List getList_1(){
            return new Vector ();
        }
    
    • 1
    • 2
    • 3

    剩下的都不需要改。这就是为什么我们使用集合时最好使用接口类型去接收,本质上还是使用多态思维让代码具有更好的扩展性与复用。

  • 相关阅读:
    ROS1云课→15主题与坐标系
    leetcode 45
    java毕业设计商品供应管理系统源码+lw文档+mybatis+系统+mysql数据库+调试
    二、sql手工注入
    值得掌握的Java代码优化技巧
    大数据开发工程师要求高么?有前景么
    make: /opt/rh/llvm-toolset-7/root/usr/bin/clang: Command not found
    1024快乐
    Java项目:JSP中华传统美食网站平台管理系统
    复星杏脉算法面经2024年5月16日面试
  • 原文地址:https://blog.csdn.net/qq_43483251/article/details/127909842