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();
}
}
结果:
解释:
动物类有一个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、多态前提:
- 继承关系、或接口实现关系
- 子类重写父类方法
- 父类引用指向子类实例对象