我有一个List,保证只包含一种类型的对象。这是由某个我无法更新的库中的一些底层代码创建的。我想基于传入的List对象创建List<ObjectType>,以便我的调用代码正在使用List<ObjectType>。
如何将List(或任何其他对象集合)转换为List<ObjectType> 是最佳方法。
如何将List(或任何其他对象集合)转换为List<ObjectType> 是最佳方法。
当与未指定泛型类型参数的遗留代码进行互操作时,请使用通配符。例如,假设您正在调用一个仅返回原始Collection
的旧库中的方法:
Collection getItems();
在你的代码中,将结果分配给使用通配符声明的变量:
Collection<?> items = widget.getItems();
这种方式可以保持类型安全,因此您不会收到任何警告。
旧代码可能会指定泛型参数应该是什么(大多数情况下在注释中)。例如:
/**
* @return the items, as a Collection of {@link Item} instances.
*/
Collection getItems();
在这种情况下,你有选择的余地。你可以将结果转换为一个Collection<Item>
,但是如果这样做,你将完全依赖第三方库,并丢弃Java泛型类型的保证:在显式转换时,任何运行时抛出的ClassCastException
都会发生。Collection<Item>
,那么就创建一个新集合,在将其转换为期望类型后添加内容。这样,如果库中存在错误,你会立即发现它,而不是在某些代码远离和更晚的地方神秘地爆炸并出现ClassCastException
。Collection<?> tmp = widget.getItems();
Collection<Item> items = new ArrayList<Item>(tmp.size());
for (Object o : tmp)
items.add((Item) o); /* Any type error will be discovered here! */
如果类型参数在编译时不知道,您可以使用Collections
类的类型检查集合工厂。
List raw = new ArrayList();
List<String> generic = (List<String>) raw;
ClassCastException
异常,而此异常不会指向列表创建的位置。 - Derek MaharList<T>
,你会得到一个"unchecked"编译器警告。我们通过将其移动到一个实用方法中解决了这个问题。public class Lists {
@SuppressWarnings({"unchecked"})
public static <T> List<T> cast(List<?> list) {
return (List<T>) list;
}
}
现在调用者不会收到任何警告,例如:
for (Element child : Lists.<Element>cast(parent.getChildren())) {
// ...
}
checkedList
工具在理论上是一个很好的想法,但实际上必须传入你期望的类非常糟糕。我希望 Java 最终能够获得运行时的泛型信息。
最好且最安全的方法是使用java.util.Collections方法'checkedList(List list, Class type)'
使用此方法,您旧列表中的所有项目将尽早进行检查。
checkedList
方法是否仅适用于新的(且为空)泛型列表?您是在建议我们在 Java 5 之前使用非泛型的 checkedList
吗?这种遗留形式无法转换为泛型列表。 - Derek Mahar试试这个:
List<ObjectType> objectsWithType = Arrays.asList((ObjectType[])wildcardObjects).toArray());
但请记住,这将产生一个固定长度的列表。如果您尝试从此列表中添加或删除元素,它将抛出错误。因此,在使用 Arrays.asList()
时一定要小心。