首页 专题 文章 代码 归档
Java 面向对象-多态
2020.02.27 17:55 2020.03.19 11:02

1. 多态

一句经典的总结:同样的引用,调用同样的方法,却做了不同的事情。

概述:

在设计一个方法时,通常希望该方法具备定的通用性。

例如要实现一个动物叫的方法,由于每种动物的叫声是不同的,因此可以在方法中接收一个动物类型的参数,当传入猫类对象时就发出猫类的叫声,传人犬类对象时就发出犬类的叫声。

在同一个方法中,这种由于参数类型不同而导致执行效果各异的现象就是多态。

在Java中为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象,根据被引用子类对象特征的不同,得到不同的运行结果。


实际例子:

动物类:

package test04;

public class Animal {

    public void shout() {
        System.out.println("动物叫...");
    }
}

猫类,继承自动物类:

package test04;

public class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("这是猫叫...");
    }
}

狗类,也继承自动物类:

package test04;

public class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("这是狗叫...");
    }
}

主方法测试:

package test04;

public class Main {

    public static void main(String[] args) {

        Animal cat = new Cat();
        Animal dog = new Dog();

        doShout(cat);//传入的是Animal类型
        doShout(dog);//传入的是Animal类型
    }

    /*第三个方法,参数是Animal类型*/
    public static void doShout(Animal animal) {
        animal.shout();
    }
}

结果:

截图-1582796489

解释:

动物类有一个shout方法,猫类和狗类都继承了该动物类,并且重写shout方法;

在Main函数中,我们分别了new了猫类和狗类,但是引用类型却是Animal父类,这是利用自动向上转型实现(见上节);

Animal cat = new Cat();
Animal dog = new Dog();

然后我们定义了一个第三方方法,参数是Animal类型,Java是强类型语言,类型不同的参数是无法调用的。

恰好,通过向上转型,就可以传入了:

/*第三个方法,参数是Animal类型*/
public static void doShout(Animal animal) {
    animal.shout();
}

这样就实现了调用同一个方法,却产生了不同的效果;

由此可见,多态不仅解决了方法同名的问题,而且还使程序变得更加灵括,从而有效地提高程序的可扩展性和可维护性。


1.1. 成员变量问题

多态写法都是:父类引用指向子类对象;

直接对象名.成员变量

Father son = new Son();

如果在父类中有一个成员变量num,那么子类中也有同名变量(类型也同),那么如果:

son.num指向的是谁?父类中的num

这是因为规则:看等号左边是谁,优先使用,没有则向上寻找;

直接对象名.方法名间接访问

通过方法间接访问成员变量,如:showNum()

那么显示的是?看该方法属于谁,就调用;没有则向上寻找;

也即:如果子类重写了showNum方法,那么调用子类的,如果子类没有重写,那么调用父类的showNum

1.2. 子类特有问题

父类引用指向子类对象,一般情况下没什么问题!

也即如下写法:

动物类

public class Animal {
    public void shout() {
        System.out.println("动物叫...");
    }
}

狗类:继承自动物类

public class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫...");
    }
}

测试

public static void main(String[] args) {
    Animal dog = new Dog();
    dog.shout();
}

没有一点问题,但是如果子类有自己特有的方法呢?

public class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫...");
    }

    public void dogSay() {
        System.out.println("狗说...");
    }
}

这里的dogSay是子类Dog特有的一个方法,如果还是

public static void main(String[] args) {
    Animal dog = new Dog();
    dog.shout();
    dog.dogSay();

}

特定dog.dogSay();会报错的!如何解决?

强制向下转型:

public static void main(String[] args) {
    Animal dog = new Dog();
    dog.shout();
    Dog d = (Dog) dog;
    d.dogSay();
}

没有问题了,但是这种做法安全吗?不安全,如果变量dog的实际类型不是Dog,强制转型是会报错的!

转型之前应该用instanceof判断下:

public static void main(String[] args) {
    Animal dog = new Dog();
    dog.shout();
    if (dog instanceof Dog) {
        Dog d = (Dog) dog;
        d.dogSay();
    }
}

至此就可以完美解决多态中子类特有的方法问题!

2. 总结

1、上面说:

Java是强类型语言,类型不同的参数是无法调用的。

那我们通过方法重载不就可以实现不同参数的传入了吗?是的,这没错。但是,这就是多个方法了。

而本文开头写的是:同样的引用,调用同样的方法,却做了不同的事情。

2、多态定义:

同样的引用,调用同样的方法,却做了不同的事情。

3、多态实现:

  • 不同的子类对父类的同一方法给出不同 的实现;
  • 父类型的引用指向子类;

4、多态前提:

  • 继承关系、或接口实现关系
  • 子类重写父类方法
  • 父类引用指向子类实例对象
本节阅读完毕! (分享
二维码图片 扫描关注我们哟