此 Java 教程是针对 JDK 8 编写的。本页面描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关 Java SE 9 及后续版本中更新的语言特性的摘要,请参阅 Java 语言更改。
有关所有 JDK 发行版的新功能、增强功能和已删除或弃用选项的信息,请参阅 JDK 发行说明。
JDK 5.0引入了Java编程语言的几个新扩展之一。其中之一是引入了泛型。
本教程是关于泛型的介绍。您可能对其他语言中类似的构造有所了解,尤其是C++的模板。如果是这样,您会发现有相似之处,但也有重要的区别。如果您对其他语言中的类似构造不熟悉,那就更好了;您可以从零开始,而无需纠正任何误解。
泛型允许您对类型进行抽象。最常见的例子是容器类型,例如Collections层次结构中的容器。
以下是这种类型的典型用法:
List myIntList = new LinkedList(); // 1 myIntList.add(new Integer(0)); // 2 Integer x = (Integer) myIntList.iterator().next(); // 3
第3行的强制类型转换有点烦人。通常,程序员知道将什么类型的数据放入了特定的列表中。然而,强制类型转换是必需的。编译器只能保证迭代器返回的是一个Object
。为了确保将其赋值给类型为Integer
的变量是类型安全的,需要进行强制类型转换。
当然,强制类型转换不仅引入了冗余代码,还可能引发运行时错误,因为程序员可能会犯错。
如果程序员能够实际表达他们的意图,并将列表标记为仅包含特定数据类型,会怎么样?这就是泛型的核心思想。以下是使用泛型给出的上述程序片段的版本:
List<Integer> myIntList = new LinkedList<Integer>(); // 1' myIntList.add(new Integer(0)); // 2' Integer x = myIntList.iterator().next(); // 3'
注意变量myIntList
的类型声明。它指定了这不仅仅是一个任意的List
,而是一个Integer
类型的List
,写作List<Integer>
。我们说List
是一个泛型接口,它接受一个类型参数,在这种情况下是Integer
。创建列表对象时,我们也要指定一个类型参数。
同时注意,第3'行的强制类型转换消失了。
现在,您可能认为我们所做的只是将冗余代码移动了一下。我们不再在第3行进行强制类型转换,而是在第1'行将Integer
作为类型参数。然而,在这里有一个非常大的区别。编译器现在可以在编译时检查程序的类型正确性。当我们说myIntList
被声明为类型List<Integer>
时,这告诉我们一些关于变量myIntList
的信息,这个信息在使用它的任何地方都是正确的,编译器会保证它。相比之下,强制类型转换告诉我们的是程序员在代码中的某个单点上认为是正确的。
尤其是在大型程序中,这种方式可以提高可读性和稳健性。