这是java.util
包中的List
和Iterator
接口的一小部分定义摘录:
public interface List <E> {
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
除了尖括号中的内容外,所有这些代码都应该很熟悉。这些是接口List
和Iterator
的形式类型参数(formal type parameters)的声明。
类型参数可以在整个泛型声明中使用,几乎可以在使用普通类型的地方使用(尽管有一些重要限制;请参见“细则”部分 。
在简介中,我们看到了泛型类型声明List
的调用,例如List<Integer>
。在该调用(通常被称为参数化类型),所有出现的形式类型参数(在这种情况下为E
)由实际类型参数(在这种情况下为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
作元素。我们将在后面的示例中看到一些其他约定。