Java教程
  • Introduction
  • Getting Started
    • The Java Technology Phenomenon
      • About the Java Technology
      • What Can Java Technology Do?
      • How Will Java Technology Change My Life?
    • The Hello World Application
    • A Closer Look at the Hello World Application
  • Learning the Java Language
    • Object-Oriented Programming Concepts
      • What Is an Object?
      • What Is a Class?
      • What Is Inheritance?
      • What Is an Interface?
      • What Is a package?
    • Language Basics
      • Java Language Keywords
    • Annotations
      • Annotations Basics
      • Declaring an Annotation Type
      • Predefined Annotation Types
      • Repeating Annotations
      • Type Annotations and Pluggable Type Systems
    • Generics
      • Why Use Generics?
      • Generic Types
        • Raw Types
      • Generic Methods
      • Bounded Type Parameters
        • Generic Methods and Bounded Type Parameters
      • Generics, Inheritance, and Subtypes
      • Type Inference
      • Wildcards
        • Upper Bounded Wildcards
        • Unbounded Wildcards
        • Lower Bounded Wildcards
        • Wildcards and Subtyping
        • Wildcard Capture and Helper Methods
        • Guidelines for Wildcard Use
      • Type Erasure
        • Erasure of Generic Types
        • Erasure of Generic Methods
        • Effects of Type Erasure and Bridge Methods
        • Non-Reifiable Types
      • Restrictions on Generics
Powered by GitBook
On this page

Was this helpful?

  1. Learning the Java Language
  2. Generics

Generics, Inheritance, and Subtypes

PreviousGeneric Methods and Bounded Type ParametersNextType Inference

Last updated 5 years ago

Was this helpful?

众所周知,只要类型兼容,我们就可以将一种类型的对象赋值给另外一个类型的对象。举例来说,我们可以将Integer类型的对象赋值给一个Object类型,因为Object类是Integer的超类之一:

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兼容的传参都是允许的:

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>吗?答案是NO,因为Box<Integer>和Box<Double>不是Box<Number>的子类型。

当使用泛型编程时会有一个普通的误解,确实一个需要理解的重要概念。

Box<Integer> is not a subtype of Box<Number> even though Integer is a subtype of Number.

Generic Classes and Subtyping

我们可以通过扩展泛型类或着实现接口来子类型化。一个类或接口的类型参数与另一类或接口的类型参数之间的关系由extends和implements语句确定。

这里使用Collections类作为例子,ArrayList<E>实现List<E>,而List<E>扩展Collection<E>。所以ArrayList<String>是List<String>的一个子类型,List<String>则是Collection<String>的子类型。只要类型传参保持不变,子类型关系就保存在类型之间。

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

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

下面这些参数化的PayloadList都是List<String>的子类:

  • PayloadList

  • PayloadList

  • PayloadList

给定两个具体的类型A和B(例如,Number和Integer),无论A和B是否相关,MyClass <A>与MyClass <B>没有关系。MyClass <A>与MyClass <B>共同的父类是Object。有关在类型参数相关时如何在两个泛型类之间创建类似子类型的关系的信息,请参考

A sample Collections hierarchy
A sample PayloadList hierarchy
Wildcards and Subtyping