泛型倾向于解决我认为在 Java 1.4 或更早版本中处理集合时的“幼稚转换”问题。在 Java 1.5+ 中,您放置的行:
ArrayList<Row> rows = new ArrayList();
会发出警告,正确的通用代码是
ArrayList<Row> rows = new ArrayList<Row>();
这告诉编译器你的 ArrayList 对象应该只包含 Row 类型。
但是,由于 Java 1.5 向后兼容大量不包含该语法的库,而是您以前的代码:
ArrayList rows = new ArrayList();
泛型显然不适用于这些旧库 - 因此泛型只是 编译时间 选项 - 1.5 和 1.4 类实际上是等效的(减去以后添加的任何内部重构/新方法),因为它们实际上是处理任何 Object 类型的 ArrayList 实现。
1.5 代码只是为您添加了直接转换。
在 1.4 代码中,假设您想要遍历 ArrayList。执行此操作的天真转换方式如下:
for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
Row row = (Row) rowIterator.next();
// Do something with the row.
}
Java 1.5 的代码完全等同于 naive cast 版本。事实是,您告诉编译器它是一行并为您执行该代码。因此,语法糖的好处更好(这对每个循环语法都使用了更新的语法,但它会生成与上述循环相同的代码):
for(Row row : rows) {
// Do something with the row
}
因此,如果您想使用仅包含行的 ArrayList,您仍然可以。但是没有办法让编译器检查 ArrayList 只包含所有行(尽管,即使编译器提供了这种检查,仍然可以发送一个ArrayList 包含其他类型的对象,因为 ArrayList 仍然只真正处理 Object 类型,并且泛型在运行时被删除 - 剩下的只是你不再看到的幼稚的转换代码。
非天真的变体是检查每个实例并自己抛出一个带有信息性消息的 ClassCastException(而不是让程序使用其默认消息抛出一个):
for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
Object shouldBeRow = rowIterator.next();
if(!(shouldBeRow instanceof Row)) {
throw new ClassCastException("The object " + shouldBeRow + " is not an instance of Row - only Rows should be present in the list!");
}
Row row = (Row) shouldBeRow;
// Do something with the row.
}
但是,通常没有人这样做 - 好的文档可以解决这个问题,因为它将提供正确集合的负担放在调用者身上,因此您可以让 JVM 抛出 ClassCastException。