Der*_*har 15 java generics list covariance
在Java中,如何转换List<?>为List<T>使用通用方法,以便我可以使用单个方法调用替换以下模式:
List untypedList = new ArrayList(); // or returned from a legacy method
List<Integer> typedList = new ArrayList<Integer>();
for (Object item: untypedList)
typedList.add((Integer)item);
Run Code Online (Sandbox Code Playgroud)
请注意,上面的代码不会生成任何类型安全警告,理想情况下,您的解决方案也不应生成任何此类警告.
如果列表Class<L>具有公共默认构造函数,以下解决方案是否可行?
public class ListUtil {
public static <T, L extends List<T>> L typedList(List<?> untypedList, Class<T> itemClass, Class<L> listClass) {
L list = null;
try {
list = listClass.newInstance();
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
}
for (Object item: untypedList)
list.add(itemClass.cast(item));
return list;
}
}
Run Code Online (Sandbox Code Playgroud)
(注意listClass.newInstance()抛出InstantiationException或者IllegalAccessException如果实例Class<L>没有公共默认构造函数.如果方法没有正确处理这些异常,可能会出现什么问题?)
笔记:
T 是结果列表中每个项目的类型.L是我想要创建的列表的类型(扩展List<T>).untypedList是"无类型"输入列表,实际上是相同的List<Object>.itemClass表示运行时类T.listClass表示运行时类L.Col*_*inD 13
我会使用番石榴和其Iterables.filter(可迭代,班)方法用一个工厂方法沿着从Lists类,如下所示:
List<?> original = ...;
List<String> typed = Lists.newArrayList(
Iterables.filter(original, String.class));
Run Code Online (Sandbox Code Playgroud)
这将实际检查原始列表中的每个对象,结果列表将仅包含给定类型(String在本例中)的实例或其子类型的那些元素.我真的认为让用户为Class结果List类型提供一个并尝试通过反射实例化它是没有意义的.
为什么不传入你想要填充的空集合<T>,而不是传入你想要实例化的列表类型?这为api的用户提供了更大的灵活性,因为使用默认构造函数并不总是理想的.(例如,也许我想要一个Set,我提供预期数量的元素,或者我想要一个排序列表,我提供比较器).
另外,作为附注,您应该始终编程到最通用的接口.在这种情况下,您的输入不需要比Iterable更具体,输出集合.
鉴于此,我会用这种方式编写方法 -
public static <T, C extends Collection<T>> C typesafeAdd(Iterable<?> from, C to, Class<T> listClass) {
for (Object item: from) {
to.add(listClass.cast(item));
}
return to;
}Run Code Online (Sandbox Code Playgroud)
那么调用代码看起来像:
public static void main(String[] args) {
List<?> untypedStringList = LegacyApi.getStringList();
List<String> typesafeStringList = typesafeAdd(untypedStringList, new ArrayList<String>(), String.class);
}
2评论在这里: