不同的对象,接受到相同的消息,产生的响应不同就是多态。
多态的前提:
必须是类与类之间有关系。要么继承,要么实现。
通常还有一个前提:存在覆盖。
多态的好处:
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要
多态的体现:重写,重载等。
重写和重载的区别:
方法的重写(override)
在子类继承父类时,子类的方法和父类的方法相同(访问修饰符,返回值类型,方法名,参数列表),方法体不同,一般是父类的该方法满足不了子类的需求所以才发生重写。这种子类的方法将父类的方法覆盖叫做重写。
方法的重载(overload)
在同一个类中,有着相同的方法名但是参数的数据类型或者参数的个数不同这两个方法就是重载。重载的目的:节省类中的命名资源和提高代码的可读性
比如说动物都有“叫”的方法,但是狗是“汪汪”,而猫是“喵喵”,当它们接收到被打的消息时,所做的响应是不同的。
案例:打动物
定义一个动物类,实现“叫”的方法
public class Animal {
public void shout(){
System.out.println("吼吼……");
}
}
定义一个狗类,继承自动物类,重写“叫”的方法
public class Dog extends Animal {
@Override
public void shout() {
System.out.println("汪汪……");
}
}
定义一个猫类
public class Cat extends Animal {
@Override
public void shout() {
System.out.println("喵喵……");
}
}
测试程序
public class Test {
public static void main(String[] args) {
Dog d = new Dog();
Cat c = new Cat();
hit(d);
hit(c);
}
private static void hit(Cat c) {
c.shout();
}
private static void hit(Dog d) {
d.shout();
}
}
在测试程序中定义了两个“打”的方法,这种做法是比较笨拙的,有几种动物就需要定义几个方法,这个可能没完没了。有没有一个一劳永逸的方法?
不要传递Dog或者Cat等对象,而是传递一个Animal类对象就可以解决上面的问题。测试程序修改为
public class Test {
public static void main(String[] args) {
Dog d = new Dog();
Cat c = new Cat();
hit(d);
hit(c);
}
private static void hit(Animal a) {
a.shout();
}
}
这里涉及两个知识点:
(1)赋值兼容性规则
hit方法形参是Animal类型,而实参是Dog或者Cat,所以类型不一致,为什么还可以呢?
所谓赋值兼容性规则,指的是凡是需要用到父类引用的地方,都可以使用它的子类引用去代替。比如某人请求派车接他,结果对方派了个三轮车去接了,虽然他可能不满意,但是也没有办法,因为对方是按照他的要求做的。
(2)多态
形参一定是父类的引用,而实参可以是它的任何一个子类的引用。