文档

Java™ 教程-Java Tutorials 中文版
泛型,继承和子类型
Trail: Learning the Java Language
Lesson: Generics (Updated)

泛型,继承和子类型

如你所知,只要类型兼容,就可以将一种类型的对象分配给另一种类型的对象。例如,你可以将 Integer 分配给 Object,因为 ObjectInteger 的超类型之一:

Object someObject = new Object();
Integer someInteger = new Integer(10);
someObject = someInteger;   // OK

在面向对象的术语中,这被称为 "是一个(is a)" 关系。由于 Integer is a (是一个)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<Number> 的参数。但是,这是什么意思?你是否可以按照预期传递 Box<Integer>Box<Double>?答案是 "否",因为 Box<Integer>Box<Double> 不是 Box<Number> 的子类型。

在使用泛型编程时,这是一个常见的误解,但这是一个重要的学习概念。

显示 Box<Integer> 不是 Box<Number> 的子类型的图表
Box<Integer> 不是 Box<Number> 的子类型,即使 IntegerNumber 的子类型。

注意: 给定两种具体类型 AB(例如,NumberInteger),MyClass<A>MyClass<B> 没有任何关系,无论 AB 是否相关。MyClass<A>MyClass<B> 的公共父类是 Object

有关如何在类型形参相关时在两个泛型类之间创建类似子类型关系的信息,请参阅 Wildcards and Subtyping

泛型类和子类型

你可以通过继承泛型类或实现泛型接口来对其进行子类型化。一个类或接口的类型形参与另一个的类型形参之间的关系由 extendsimplements 子句确定。

Collections 类为例,ArrayList<E> 实现 List<E>List<E> extends Collection<E>。所以 ArrayList<String>List<String> 的子类型,它是 Collection<String> 的子类型。只要不改变类型实参,就会在类型之间保留子类型关系。

显示样本集合层次结构的图表:ArrayList<String> 是 List<String> 的子类型,它是 Collection<String>的子类型。
Collections 示例的层次结构

现在假设我们想要定义我们自己的 list 接口 PayloadList,它将泛型类型 P 的可选值与每个元素相关联。它的声明可能如下:

interface PayloadList<E,P> extends List<E> {
  void setPayload(int index, P val);
  ...
}

PayloadList 的以下参数化是 List<String> 的子类型:

示意 PayLoadList 层次结构的示意图:PayloadList<String, String> 是 List<String> 的子类型,它是 Collection<String> 的子类型。与 PayloadList<String,String> 相同级别的是 PayloadList<String, Integer> 和 PayloadList<String, Exceptions>。
PayloadList 示例的层次结构

Previous page: Generic Methods and Bounded Type Parameters
Next page: Type Inference