众所周知,只要类型兼容,就可以将一种类型的对象分配给另一种类型的对象。例如,你可以指定一个Integer给一个Object,因为Object是Integer的一个超类型(supertypes):
Object someObject = new Object();
Integer someInteger = new Integer(10);
someObject = someInteger; // OK
在面向对象的术语中,这称为“是(is a)”关系。由于Integer 是_Object 的_一种,因此允许分配。但是Integer也是Number的一种,因此以下代码也有效:
public void someMethod(Number n) { /* ... */ }
someMethod(new Integer(10)); // OK
someMethod(new Double(10.1)); // OK
泛型也是如此。您可以执行泛型类型调用,将Number用作其类型实参,如果其他实参和Number兼容,则随后可以进行add方法的任意调用:
Box<Number> box = new Box<Number>();
box.add(new Integer(10)); // OK
box.add(new Double(10.1)); // OK
现在考虑以下方法:
public void boxTest(Box<Number> n) { /* ... */ }
它接受哪种类型的实参?通过查看其签名,您可以看到它接受一个类型为Box
在使用泛型进行编程时,这是一个常见的误解,但它是一个重要的概念。
Box
注意: 给定两个具体类型A和B(例如Number和Integer),无论A和B是否相关,MyClass 与MyClass 没有关系。MyClass 和MyClass 的公共父对象是Object。 有关在类型参数相关时,如何在两个泛型类之间创建类似子类型关系的信息,请参见 通配符和子类型。
泛型类和子类型
您可以通过扩展或实现来创建泛型类或泛型接口的子类型。一个类或接口的类型形参与另一类或接口的类型形参之间的关系由extends和Implements子句确定。
以Collections类为例,ArrayList
样本集合层次结构
现在假设我们要定义自己的列表接口PayloadList,该接口将泛型P的可选值与每个元素相关联。它的声明可能看起来像:
interface PayloadList<E,P> extends List<E> {
void setPayload(int index, P val);
...
}
PayloadList 的以下参数化是List
PayloadList<String,String>
PayloadList<String,Integer>
PayloadList<String,Exception>
示例PayloadList层次结构