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

  • 相关阅读:
    Verilog非阻塞赋值的仿真/综合问题 (Nonblocking Assignments in Verilog Synthesis)上
    异步FIFO结构及FPGA设计 跨时钟域设计
    FPGA管脚分配需要考虑的因素
    An Introduction to Delta Sigma Converters (DeltaSigma转换器 上篇)
    An Introduction to Delta Sigma Converters (DeltaSigma转换器 下篇)
    中国通信简史 (下)
    谈谈德国大学的电子专业
    中国通信简史 (上)
    Verilog学习笔记
    Verilog非阻塞赋值的仿真/综合问题(Nonblocking Assignments in Verilog Synthesis) 下
  • 原文地址:https://www.cnblogs.com/ibelieve618/p/6443291.html
Copyright © 2011-2022 走看看