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
,表示元素,就像上面的例子中一样。我们将在以后的例子中看到一些其他的约定。