Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
请参阅Java语言更改,了解Java SE 9及后续版本中更新的语言功能的摘要。
请参阅JDK发行说明,了解所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息。
以下是包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的形式类型参数的声明。
类型参数可以在泛型声明中的许多地方使用,就像你使用普通类型一样(虽然有一些重要的限制;参见详细说明部分)。
在介绍中,我们看到了泛型类型声明List的调用,比如List<Integer>。在调用(通常称为参数化类型)中,形式类型参数(在这个例子中是E)的所有出现都被实际类型参数(在这个例子中是Integer)替换。
你可以想象List<Integer>代表的是一个List的版本,其中E被Integer统一替换:
public interface IntegerList {
void add(Integer x);
Iterator<Integer> iterator();
}
这种直觉可能有帮助,但也是误导的。
它是有帮助的,因为参数化类型List<Integer>确实有看起来像这个展开的方法。
它是误导的,因为泛型的声明实际上永远不会以这种方式展开。代码没有多个副本 - 源代码中没有,二进制代码中没有,磁盘上没有,内存中也没有。如果你是C++程序员,你会明白这与C++模板非常不同。
泛型类型声明只会被编译一次,并且变成一个单独的类文件,就像普通的类或接口声明一样。
类型参数类似于方法或构造函数中使用的普通参数。就像方法有描述它所操作的值类型的形式值参数一样,泛型声明有形式类型参数。当调用方法时,实际参数会替换形式参数,并且方法体被计算。当调用泛型声明时,实际类型参数会替换形式类型参数。
关于命名约定的说明。我们建议您为形式类型参数使用简洁(如果可能的话,使用单个字符)但富有表现力的名称。最好避免在这些名称中使用小写字符,以便轻松区分形式类型参数和普通类和接口。许多容器类型使用E,表示元素,就像上面的例子中一样。我们将在以后的例子中看到一些其他的约定。