🥖多态是什么?
w3school上对多态是这样描述的:
Polymorphism means "many forms", and it occurs when we have many classes that are related to each other by inheritance.
实际上,多态就是“多种形式”,它具有以下两层意义:
多态是同一个行为具有不同的表现形式或形态的能力
同一方法可以根据发送对象的不同而采用不同的行为方式
多态具有三种类型:
Ad hoc polymorphism (特殊多态)
Parametric polymorphism (参数化多态)
Subtyping (also called subtype polymorphism or inclusion polymorphism 子类型多态、包含多态)
接下来,我将对三种多态逐一分析:
🫓多态的三种类型:
🚝Ad hoc polymorphism (特殊多态)
这种多态发生在方法具有不同的实现时,在常见的编程语言中常常通过方法重载(overloading)实现。
public class OverloadExample {
public static String add(String c, String d) {
return c.concat(d);
}
public static String add(String c, String d, String e) {
return c.concat(d).concat(e);
}
public static int add(int a, int b) {
return a + b;
}
}
在上述代码中,add()方法具有多种实现,他们的参数列表不同(包括参数的数量不同以及参数的数据类型不同,但不包括参数名称不同),编译器会将其视作不同的方法。
在具体使用add()方法时,根据参数的不同,会调用相应的方法:
public static void main(String args[]) {
System.out.println(add("C", "D"));
System.out.println(add("C", "D", "E"));
System.out.println(add(2, 3));
}
值得注意的是,方法的重载也可以发生在子类和父类中,观察下面的例子:
class Animal {
public void eat() {
}
}
class Horse extends Animal {
public void eat(String food) {
}
}
在这个例子中,子类Horse重载了父类的eat()方法,相当于:
class Animal {
public void eat() {
}
}
class Horse extends Animal {
public void eat() {
}
public void eat(String food) {
}
}
将其实例化,调用eat()方法,会有以下结果:
Animal a = new Animal();
a.eat();
a.eat("food");//编译报错,因为Animal类没有eat(String food)方法
Animal b = new Horse();
b.eat();
b.eat("food");//编译报错,因为在编译阶段对象b会被视作一个Animal类,报错原因同上
Horse c = new Horse();
c.eat();
c.eat("food");
对象b会被视作一个Animal类。
最后,给出方法重载(Overloading)与方法重写(Overriding)的区别:
![](https://img-blog.csdnimg.cn/img_convert/80c3abfb7c55a122af76ff07e2391616.png)
🚞Parametric polymorphism (参数化多态)
参数化多态就是函数工作过程中的数据结构支持多种类型,在Java中通常使用“泛型”来实现。
在Java中有以下几种泛型:
泛型变量
泛型类
泛型接口
泛型方法
我们逐一分析:
🐳泛型变量:
见如下例子:
public class GenericClass<T>{
//t是一个泛型成员变量
private T t;
public void function(T t){
}
在这个例子中T是一个泛型变量,这意味着T可以是任意的引用数据类型(详情可见笔者博文:数据类型与类型检验)。
🐋泛型类:
//GenericClass是一个泛型类
public class GenericClass<T>{
//t是一个泛型成员变量
private T t;
public void function(T t){
}
仍然是刚刚的例子,GenericClass类在声明时添加了<T>这就是说,这个类是一个泛型类,具有一个泛型T。类的泛型也可以有多个,语法为:
[访问修饰符] class 类名<泛型1,泛型2,...> {
泛型1 泛型成员1 ;
泛型2 泛型成员2;
...
}
🐬泛型接口:
类似于泛型类,就是在接口上定义泛型,作用于方法:
public interface GenericInterface<T> {
public T get();
public void set(T t);
public T delete(T t);
default T defaultFunction(T t){
return t;
}
}
🐟泛型函数:
写法是函数返回类型旁加上泛型,用于实现一个通用数据类型的函数:
public class GenericFunction {
public <T> void function(T t) {
}
public <T> T functionTwo(T t) {
return t;
}
public <T> String functionThree(T t) {
return "";
}
}
🚋Subtyping Polymorphism(子类型多态或包含多态)
Java中的“子类”、“父类”等概念也是多态的体现。
一个子类对象B一定是“父类”(包括对接口的实现,下同),举个例子,若子类“猫”继承自父类“动物”,则“猫”的实例B一定是“动物”。
另一方面,这种子类与父类间的继承关系要求子类的Spec一定要强于其父类的Spec。
以Collection为例:
![](https://img-blog.csdnimg.cn/img_convert/1c02bd0f887306cae7f59210d4ec513b.png)
ArrayList、LinkedList一定是List,其Spec一定要强于List的Spec(显然,这是符合客观世界规律的)。
🥨多态的作用
最后,让我们再来复盘下多态,讲讲为什么要这样设计。
多态就是“多种形式”,它具有以下两层意义:
多态是同一个行为具有不同的表现形式或形态的能力
同一方法可以根据发送对象的不同而采用不同的行为方式
这一设计思想是符合客观世界规律的,其具有以下作用:
提高了代码的维护性(继承保证)。
提高了代码的扩展性(由多态保证)。
泛型使程序员能够实现通用算法,增强了代码的复用。
通过使用泛型,程序员可以实现适用于不同类型集合的泛型算法,安全且易于阅读。
使得代码更为灵活