Generics, Inheritance, and Subtypes
Last updated
Last updated
众所周知,只要类型兼容,我们就可以将一种类型的对象赋值给另外一个类型的对象。举例来说,我们可以将Integer
类型的对象赋值给一个Object
类型,因为Object
类是Integer
的超类之一:
在面向对象术语中,我们称这种关系为is a
(某某是一种/个)。因为一个Integer
是一种Object
,所以赋值是允许的,但是Integer
也是一种Number
,所以下面的代码也是成立的:
在泛型中也同样成立。下面我们使泛型类型调用,Number
作为类型传参,那么后续所有和Number
兼容的传参都是允许的:
现在我们来看下面这个函数:
它能接受什么类型的传参?从定义上看,我们能发现它接受单个类型为Box<Number>
的传参。这意味什么?你可能会想我们可以传入Box<Integer>
或者Box<Double>
吗?答案是NO
,因为Box<Integer>
和Box<Double>
不是Box<Number>
的子类型。
当使用泛型编程时会有一个普通的误解,确实一个需要理解的重要概念。
给定两个具体的类型A和B(例如,
Number
和Integer
),无论A和B是否相关,MyClass <A>
与MyClass <B>
没有关系。MyClass <A>
与MyClass <B>
共同的父类是Object
。有关在类型参数相关时如何在两个泛型类之间创建类似子类型的关系的信息,请参考Wildcards and Subtyping
我们可以通过扩展泛型类或着实现接口来子类型化。一个类或接口的类型参数与另一类或接口的类型参数之间的关系由extends
和implements
语句确定。
这里使用Collections
类作为例子,ArrayList<E>
实现List<E>
,而List<E>
扩展Collection<E>
。所以ArrayList<String>
是List<String>
的一个子类型,List<String>
则是Collection<String>
的子类型。只要类型传参保持不变,子类型关系就保存在类型之间。
现在想象一下,我们想要定义我们自己的list接口PayloadList
,它将泛型类型为P
的可选值与每个元素相关联。它的声明如下:
下面这些参数化的PayloadList
都是List<String>
的子类:
PayloadList
PayloadList
PayloadList