多态

一、什么是多态

“多态”是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

 

posted @ 2017-02-26 23:49  自学开发的老司机  阅读(914)  评论(1编辑  收藏  举报