文档

Java™ 教程-Java Tutorials 中文版
定义简单泛型
Trail: Bonus
Lesson: Generics

定义简单泛型

以下是软件包 java.util 中接口 ListIterator 定义的片段:

public interface List <E> {
    void add(E x);
    Iterator<E> iterator();
}

public interface Iterator<E> {
    E next();
    boolean hasNext();
}

这个代码应该都很熟悉,除了尖括号中的东西。这些是接口 ListIteratorformal type parameters (形式类型形参) 的声明。

类型形参可以在整个泛型声明中使用,几乎可以使用普通类型(尽管有一些重要的限制;请参阅 The Fine Print 部分。

在简介中,我们看到了泛型类型声明 Listinvocations (调用),例如 List<Integer>。在调用中(通常称为 parameterized type (参数化类型)),所有匹配项的形式类型形参(在本例中为 E)都被 actual type argument (实际类型实参替换)(在这种情况下,Integer)。

你可以想象 List<Integer> 代表 List 的版本,其中 E 已被 Integer 统一替换:

public interface IntegerList {
    void add(Integer x);
    Iterator<Integer> iterator();
}

这种直觉可能会有所帮助,但也会产生误导。

这很有用,因为参数化类型 List<Integer> 确实具有看起来像这个扩展的方法。

这是误导性的,因为泛型的声明从未以这种方式实际扩展。没有多个代码副本 - 在源代码,二进制代码,磁盘和内存都没有。如果你是 C++ 程序员,你会明白这与 C++ 模板非常不同。

泛型类型声明一次性编译,并转换为单个类文件,就像普通的类或接口声明一样。

类型形参类似于方法或构造函数中使用的普通参数。与方法具有 formal value parameters (形式值参数) 描述其操作的值的类型非常相似,泛型声明具有形式类型形参。调用方法时,actual arguments (实际参数) 将替换形式参数,并计算方法体。调用泛型声明时,实际类型实参将替换形式类型形参。

注意命名规范。我们建议你使用简洁(单个字符,如果可能)但能引起共鸣的的名称作为形式类型形参。最好避免使用这些名称中的小写字符,这样可以很容易地将形式类型形参与普通类和接口区分开来。许多容器类型使用 E 作为元素,如上例所示。我们将在后面的示例中看到一些其他规范。


Previous page: Introduction
Next page: Generics and Subtyping