zoukankan      html  css  js  c++  java
  • 多态

    一、什么是多态

    “多态”是JAVA的一种重要特性,可以理解为事物存在的多种形态。

    不过,这只是字面上来理解,等于废话。那么究竟何为多种形态呢,接下来,举一个现实生活中的例子。

    比如,动物里有猫和狗。猫摆在面前,你可说它是猫,也可以说它是动物。

    说它是猫时,用JAVA语句表示即   猫 x=new 猫;

    说它是动物时,用JAVA语句表示即  动物 x=new 猫;

    这样,实体x即具备猫的类型,也具备动物类型。但必须一个前提,即“猫”必须是“动物”中的一种,如果“狗 x=new 猫”就不对了。

    通过以上的例子,我们可以看出,实体除了具备本类类型,还可以具备其它类型。这种是“多态”。

    先看以下代码,这是使用非多态方式编写

    代码如下:

    package com.duotai;
    
    public class DuoTaiDemo {
    
        public static void main(String[] args) {
    
            myFun(new Cat());
            myFun(new Dog());
            myFun(new Pig());
        }
    
        // 动物“吃”的功能提取出来封装成函数
        public static void myFun(Cat c) {
            c.eat();
        }
    
        public static void myFun(Dog d) {
            d.eat();
        }
    
        public static void myFun(Pig p) {
            p.eat();
        }
    
    }
    
    // 以下定义抽象类,定义了动物有“吃”的功能
    abstract class Animal {
        abstract void eat(); // 动物吃什么不知道,定义成抽象。定义体系中的基本功能。只要继承了这个类,必有此功能。
    }
    
    // 以定义具体类,复写动物的吃的功能,并有自己独特的功能
    class Cat extends Animal {
        public void eat() { // 复写Animal类的eat方法
            System.out.println("猫吃鱼");
        }
    
        public void catchMouse() { // 自己特有的方法
            System.out.println("猫抓老鼠");
    
        }
    }
    
    class Dog extends Animal {
        public void eat() { // 复写Animal类的eat方法
            System.out.println("狗吃骨头");
        }
    
        public void kanJia() { // 自己特有的方法
            System.out.println("看家");
        }
    }
    
    class Pig extends Animal {
        public void eat() { // 复写Animal类的eat方法
            System.out.println("猪吃饲料");
        }
    
        public void gongDi() { // 自己特有的方法
            System.out.println("拱地");
        }
    }

    以上代码,定义了一个“动物”类,其有一个“吃”的功能,但是由于每种动物吃的方式都不一样,所以定义成抽象类。以后让具体的动物去复写。

    然后,定义了三个继承类,“猫”“狗”“猪”,复写了动物的“吃”的功能。

    主函数调用时,要建立子类对的引用对象,再调用吃的方式。

    这样编写时,会有一个弊端,那就是继承的子类如果增加时,则要修改主函数中的“吃”的代码。子类越多,这端代码就越长,扩展性比较弱。

    如何优化呢?

    子类“猫”,继承了“动物”类,是动物中的一种,那就可以用“动物”的引用来指向子类实例,即Aniaml c=new cat,c.eat(),运行结果是子类的,因为父类中有,子类中也有,就运行子类的eat(),因为子类复写了。这就是一个事物具备多种形态。

    代码简化如下:

    package com.duotai;
    
    public class DuoTaiDemo {
    
        public static void main(String[] args) {
    
            myFun(new Cat());
            myFun(new Dog());
            myFun(new Pig());
        }
    
        // 动物“吃”的功能提取出来封装成函数
        public static void myFun(Animal a){        //只要定义Animal即可。相当于Animal a=new Cat();
            a.eat();
        }
    
    }
    
    // 以下定义抽象类,定义了动物有“吃”的功能
    abstract class Animal {
        abstract void eat(); // 动物吃什么不知道,定义成抽象。定义体系中的基本功能。只要继承了这个类,必有此功能。
    }
    
    // 以定义具体类,复写动物的吃的功能,并有自己独特的功能
    class Cat extends Animal {
        public void eat() { // 复写Animal类的eat方法
            System.out.println("猫吃鱼");
        }
    
        public void catchMouse() { // 自己特有的方法
            System.out.println("猫抓老鼠");
    
        }
    }
    
    class Dog extends Animal {
        public void eat() { // 复写Animal类的eat方法
            System.out.println("狗吃骨头");
        }
    
        public void kanJia() { // 自己特有的方法
            System.out.println("看家");
        }
    }
    
    class Pig extends Animal {
        public void eat() { // 复写Animal类的eat方法
            System.out.println("猪吃饲料");
        }
    
        public void gongDi() { // 自己特有的方法
            System.out.println("拱地");
        }
    }

    二、多态的代码提现形式

      父类的引用引向自己的子类对象。

      父类的引用也可以接收自己的子类对象。如以上代码中:Animal a=new Cat()

    三、多态的作用

      提高了程序的扩展性

    四、多态的前提

      类与类有关系,必须是继承或是实现。如以上代码中,Cat、Dog、Pig类都继承了Animal类

      通常还有一个前提,就是“复写”。如以上代码中,子父类中都有eat()方法,子类复写父类。

    五、多态的弊端

      提高了扩展性,但是只能是父类的引用访问父类中的成员

    六、多类中数据的转型

      在基本数据类型中,存在着数据类型提升现象,如double=2.3+1,会将1由int提升为double

      在多类中,引用数据也存在数据提升。如以上Animal a=new Cat()中,Animal是父类型,Cat是子类型,将Cat提升为Animal,称为向上转型。

      如果想要调用调用猫的特有方法(抓老鼠)时,可以强制将父类的引用转成子类对象。

      我们能转换的是父类引用指向自己的子类对象,该引用可以被提升,也可被强制向下转换

      如下:

    Animal c=new Cat();//
    Cat c1=(Cat)c;        //向下转型
    c1.catchMouse();    //输出猫的特有方法

    在多态中,成员函数的特点:

    1、编辑时期,参阅引用型变量所属的类中是否有调用方法。如果有编译通过,否则编译失败。

    如下:Fu f = new Zi(),f所属的Fu中只有method1和method2,所以输出method3会编辑失败。

    2、在运行时间,参阅对象所属的类中是否有调用方法。

    如下:

    Fu f = new Zi();
    f.method1();
    f.method2();

    调用的是Zi类的方法,

    简单总结,成员函数在多态调用时,编辑看左边,运行看右边

    如下:

    Fu类有method1和method2两个方法

    Zi类中有method1和method3两个方法

    Zi类中method1复写了Fu类中的method1,Zi类有三个方法

    package com.duotai2;
    
    public class DuoTaiDemo {
    
        public static void main(String[] args) {
            Fu f = new Zi();
            f.method1();
            f.method2();
            // f.method3();   //编译失败     
    
        }
    
    }
    
    class Fu {
        void method1() {        //
            System.out.println("fu_method_1");
        }
    
        void method2() {        //
            System.out.println("fu_method_2");
        }
    }
    
    class Zi extends Fu {
        void method1() {        //复写
            System.out.println("zi_method_1");
        }
    
        void method3() {        //
            System.out.println("zi_method_3");
        }
    
    }

    输出:

    zi_method_1
    fu_method_2

    在多态中,成员变量的特点:

    无论编辑和运行,只参考左边。如下

    package com.duotai2;
    
    public class DuoTaiDemo {
    
        public static void main(String[] args) {
            Fu f = new Zi();
            System.out.println(f.num);
            Zi z=new Zi();
            System.out.println(z.num);
        }
    }
    
    class Fu {
        int num=5;
    }
    
    class Zi extends Fu {
        int num=8;
    }

    输出:

    5

    8

    在多态中,静态成员函数的特点:

    无论编辑和运行,只参考左边。因为静态方法不需要创建对象,只要类名调用即可。

    如下

    public class DuoTaiDemo {
    
        public static void main(String[] args) {
            Fu f = new Zi();
            f.method4();
            
            Zi z=new Zi();
            z.method4();
        }
    }
    
    class Fu {
        static void method4() {        //
            System.out.println("fu_method_4");
        }
    }
    
    class Zi extends Fu {
      static void method4() {        //
            System.out.println("zi_method_4");
        }
    
    }

    输出:

    fu_method_4
    zi_method_4

  • 相关阅读:
    另一种保证单次插入回文自动机复杂度的做法
    loj #6070. 「2017 山东一轮集训 Day4」基因
    求第一类斯特林数的一行
    NOIP2018游记
    HDU3377 Plan
    【BZOJ】1830: [AHOI2008]Y型项链
    【BZOJ】1832: [AHOI2008]聚会
    【BZOJ】1831: [AHOI2008]逆序对
    【BZOJ】1085: [SCOI2005]骑士精神
    【BZOJ】1798: [Ahoi2009]Seq 维护序列seq
  • 原文地址:https://www.cnblogs.com/ibelieve618/p/6443291.html
Copyright © 2011-2022 走看看