Documentation

The Java™ Tutorials
Hide TOC
Generics, Inheritance, and Subtypes泛型、继承和子类型
Trail: Learning the Java Language
Lesson: Generics (Updated)

Generics, Inheritance, and Subtypes泛型、继承和子类型

As you already know, it is possible to assign an object of one type to an object of another type provided that the types are compatible. 如您所知,可以将一种类型的对象分配给另一种类型的对象,前提是这些类型是兼容的。For example, you can assign an Integer to an Object, since Object is one of Integer's supertypes:例如,可以将Integer指定给Object,因为ObjectInteger的超类型之一:

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

In object-oriented terminology, this is called an "is a" relationship. 在面向对象的术语中,这称为“是一个”关系。Since an Integer is a kind of Object, the assignment is allowed. 由于Integer是一种Object,因此允许赋值。But Integer is also a kind of Number, so the following code is valid as well:但是Integer也是一种Number,所以下面的代码也是有效的:

public void someMethod(Number n) { /* ... */ }

someMethod(new Integer(10));   // OK
someMethod(new Double(10.1));   // OK

The same is also true with generics. 泛型也是如此。You can perform a generic type invocation, passing Number as its type argument, and any subsequent invocation of add will be allowed if the argument is compatible with Number:您可以执行泛型类型调用,将Number作为其类型参数传递,如果该参数与Number兼容,则允许任何后续的add调用:

Box<Number> box = new Box<Number>();
box.add(new Integer(10));   // OK
box.add(new Double(10.1));  // OK

Now consider the following method:现在考虑以下方法:

public void boxTest(Box<Number> n) { /* ... */ }

What type of argument does it accept? 它接受哪种类型的形参?By looking at its signature, you can see that it accepts a single argument whose type is Box<Number>. 通过查看其签名,您可以看到它接受一个类型为Box<Number>的形参。But what does that mean? 但这意味着什么?Are you allowed to pass in Box<Integer> or Box<Double>, as you might expect? 是否被允许传入Box<Integer>Box<Double>The answer is "no", because Box<Integer> and Box<Double> are not subtypes of Box<Number>.答案是“不”,因为Box<Integer>Box<Double>不是Box<Number>的子类型。

This is a common misunderstanding when it comes to programming with generics, but it is an important concept to learn.在使用泛型编程时,这是一个常见的误解,但这是一个需要学习的重要概念。

diagram showing that Box<Integer> is not a subtype of Box<Number>
Box<Integer> is not a subtype of Box<Number> even though Integer is a subtype of Number.Box<Integer>不是Box<Number>的子类型,虽然IntegerNumber的子类型。

Note: Given two concrete types A and B (for example, Number and Integer), MyClass<A> has no relationship to MyClass<B>, regardless of whether or not A and B are related. 给定两种具体类型AB(例如,NumberInteger),MyClass<A>MyClass<B>没有关系,无论AB是否相关。The common parent of MyClass<A> and MyClass<B> is Object. MyClass<A>MyClass<B>的公共父级是Object

For information on how to create a subtype-like relationship between two generic classes when the type parameters are related, see Wildcards and Subtyping. 有关在类型参数相关时如何在两个泛型类之间创建类似子类型的关系的信息,请参阅通配符和子类型

Generic Classes and Subtyping泛型类和子类型

You can subtype a generic class or interface by extending or implementing it. 可以通过扩展或实现泛型类或接口来对其进行子类型化。The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.一个类或接口的类型参数与另一个类或接口的类型参数之间的关系由extendsimplements子句确定。

Using the Collections classes as an example, ArrayList<E> implements List<E>, and List<E> extends Collection<E>. Collections类为例,ArrayList<E>实现了List<E>,而List<E>扩展了Collection<E>So ArrayList<String> is a subtype of List<String>, which is a subtype of Collection<String>. 所以ArrayList<String>List<String>的子类,而List<String>又是Collection<String>的子类。So long as you do not vary the type argument, the subtyping relationship is preserved between the types.只要不改变类型参数,类型之间的子类型关系就会保持不变。

diagram showing a sample collections hierarchy: ArrayList<String> is a subtype of List<String>, which is a subtype of Collection<String>.
A sample Collections hierarchy样本Collections层次结构

Now imagine we want to define our own list interface, PayloadList, that associates an optional value of generic type P with each element. 现在假设我们想要定义自己的列表接口PayloadList,它将泛型类型P的可选值与每个元素相关联。Its declaration might look like:其声明可能如下所示:

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

The following parameterizations of PayloadList are subtypes of List<String>:以下的PayloadList参数化是List<String>的子类型:

diagram showing an example PayLoadList hierarchy: PayloadList<String, String> is a subtype of List<String>, which is a subtype of Collection<String>. At the same level of PayloadList<String,String> is PayloadList<String, Integer> and PayloadList<String, Exceptions>.
A sample PayloadList hierarchy样本PayloadList层次结构

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