Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
JDK 5.0 引入了 Java 编程语言的几个新扩展。其中之一是 generics (泛型) 的引入。
这条路径是对泛型的介绍。你可能熟悉其他语言的类似结构,最常见的是 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
是一个带有 type parameter (类型形参) 的泛型接口 - 在这种情况下,Integer
。我们还在创建列表对象时指定了类型形参。
另请注意,第 3 行的强制转换已经消失。
现在,你可能会认为我们所取得的成就就是去除了杂乱无章。我们将 Integer
作为第 1 行的类型形参,而不是第 3 行的强制转换为 Integer
。但是,这里有很大的不同。编译器现在可以在编译时检查程序的类型正确性。当我们说 myIntList
用类型 List<Integer>
声明时,这告诉我们一些关于变量 myIntList
的信息,无论它在何时何处被使用都保持为真,编译器将保证它。相比之下,强制转换告诉我们程序员认为代码中的单个点是正确的。
最终的效果,提高了可读性和稳健性,特别是在大型程序中。