这篇文章最初发表在我的博客上:
https://pleasefindencoded.blogspot.com/2020/04/post-79-what-some-people-dont-know.html
在编程的上下文中,多态性意味着-抽象意义上-当编程构造或部分代码时,例如 类或方法,可以应用于不同类型的多个对象。
通常,这是大多数人的知识的终点。 大多数人不知道有不同种类的多态性。 在这篇文章中,我将解释不同类型的多态性,并讨论它们各自的优缺点:
Subtype-Polymorphism
如果人们谈论多态,通常指的是这种类型的多态。 这也是最简单的多态性。 子类型化时,子类型的对象可在使用父类型的任何地方使用。 例如:
类Supertype {} 类子类型扩展超类型{} ... 超型sup1 =新的Supertype(); 超型sup2 =新的Subtype();
在上面的示例中,可以在使用超类型的情况下使用子类型。
另一个例子:
class MyObject1 {}
class MyObject2 {}
MyObject1 o1 = new MyObject1();
MyObject2 o2 = new MyObject2();
List和lt;Object> obList = new ArrayList<>();
obList.add(o1);
obList.add(o2);
obList.add(2);
obList.add("hello");
在上面的例子中obList
可以使用不同类型的对象-从自定义对象到数字再到字符串。
优点
- 亚型多态性给您带来灵活性
缺点
- 很难限制灵活性
- 您将失去类型安全性,因为您只能控制允许将哪个对象添加到容器中,并且如果您从容器中取出一个对象,则必须将其强制转换为原始类型,以便在有意义的情况下使用它 办法
Parametic Polymorphism
有时,您想为不同类型重用一个类,但又不想为每种类型编写自己的类。 因此,基本上,您只想将某些参数换成特定类型。 这就是参数多态性。
创建类时,请设置泛型类型Ť
。 在类中,您将泛型类型视为其他任何类型。 初始化时,将通用类型T指定为特定类型。 例如:
public class MyObject1<T> {
T obj;
void setObj(T obj) {
this.obj = obj;
}
T getObj() {
return this.obj;
}
}
假设您只想将此类应用于Integers,然后按如下所示对其进行初始化:
MyObject1<Integer> object1 = new MyObject1<Integer>();
在另一个实例上,您想重用相同的类,但对于另一种类型,则可以使用不同的类对其进行初始化:
MyObject1<String> object2 = new MyObject1<String>();
您不仅可以对一种类型使用此技术,还可以对多种类型使用此技术。 例如:
public class KeyValue<K, V> {
private K key;
private V value;
void setKeyValue(K key, V value) {
this.key = key;
this.value = value;
}
K getKey() {
return this.key;
}
V getValue() {
return this.value;
}
}
优点
- 通常在编译时进行更强大的类型分析
缺点
- 与子类型多态相比,参数多态提供的灵活性较小
- 通用参数不知道最后将要应用的类型的属性和方法
Limited parametric polymorphism
有限的参数多态性建立在参数多态性的基础上,通过定义类型的上限,您可以将类型参数限制为特定类型。 例如,当您想要构建不同类型的容器并且需要事先了解某些属性或方法的存在时,这将非常有用。
例如,您有一篮子不同的食品,并且想知道这些元素中最古老的元素。 使用有限的参数多态性,您可以这样实现:
公共接口老化{
日期getBestBeforeDate();
}
public class FoodBasket<T 延伸 Ageable> {
private T oldestFood;
public void put(T food) {
if (oldestFood == null ||
food.getBestBeforeDate().compareTo(oldestFood.getBestBeforeDate()) < 0) {
oldestFood = food;
}
}
public T getOldestFood() {
return oldestFood;
}
}
通过使用extends
我们正在为我们的类型创建一个上限。 因此,我们知道我们的类型必须具有在超类resp中定义的属性或方法。 界面并可以使用它们。
假设您想将篮子用于特定种类的食物,并希望通过其他功能对其进行扩展,那么您可以这样做:
公共类Egg实现了Ageable {
私人日期bestBeforeDate;
鸡蛋(Date bestBeforeDate){
this.bestBeforeDate = bestBeforeDate;
}
@Override
公开日期getBestBeforeDate(){
返回this.bestBeforeDate;
}
}
public class OldEggsBasket extends FoodBasket<Egg> {
// additional functions
}
类型也可以实现多个接口。 接口之间用与号分隔&
:
公共接口可打印{
无效print();
}
public class FoodBasket<T extends Ageable & Printable> {
private T oldestFood;
public void put(T food) {
if (oldestFood == null ||
food.getBestBeforeDate().compareTo(oldestFood.getBestBeforeDate()) < 0) {
oldestFood = food;
}
food.print();
}
//...
}
优点
- 编写可重用的代码,例如 库类,供其他程序员使用,他们可以根据需要进行参数化
缺点
- 与上述多态性相比,灵活性较差
Ad-hoc Polymorphism
大多数开发人员可能已经以不同的名称知道了这个概念:重载。 通过重载,您将为不同的签名提供具有相同名称的不同方法。 最常见的一种是加号(+)运算符。
优点
- (重载)方法的命名灵活性
缺点
- 没有代码重用。 因此,与其他类型的多态性不同,它并不是真正被认为是多态性的
我很感兴趣您是否知道每种多态类型的更多优点和缺点。