我发现了一个到目前为止无法解释的奇怪案例。
public static void main(String[] args) {
LinkedList<Integer> a = new LinkedList<>();
a.add(2);
a.add(3);
a.add(4);
for (ArrayList ax : getBatches(a)){
System.out.println(ax);
}
}
private static ArrayList<ArrayList<Integer>> getBatches(List<Integer> optionIds) {
return new ArrayList(Arrays.asList(optionIds));
}
执行的结果是:
线程“主”中的异常java.lang.ClassCastException:无法将java.util.LinkedList强制转换为java.util.ArrayList
for循环中会出现异常。
问题是:如何?返回类型为ArrayList
答案 0 :(得分:5)
您的方法返回原始的ArrayList
,这就是编译器允许它的原因。但是,在运行时,尝试将LinkedList
(您传递给getBatches
方法的实例)强制转换为ArrayList
,从而导致ClassCastException
。
如果您将方法更改为:
private static ArrayList<ArrayList<Integer>> getBatches(List<Integer> optionIds) {
return new ArrayList<>(Arrays.asList(optionIds));
}
您将收到编译错误。
为避免编译和运行时错误,您需要将传递给方法的List
转换为ArrayList
:
private static ArrayList<ArrayList<Integer>> getBatches(List<Integer> optionIds) {
return new ArrayList<>(Arrays.asList(new ArrayList<>(optionIds)));
}
这将返回一个ArrayList
,其单个元素是一个ArrayList
,其中包含与传递给该方法的List
相同的元素。
答案 1 :(得分:2)
getBatches()
返回通用类型为ArrayList<Integer>
的ArrayList。 Arrays.asList()
的返回类型是一个List
接口。为了从List到ArrayList进行隐式转换。问题是您不能直接将ArrayList强制转换为LinkedList。
解决此问题相对简单。而不是通过ArrayList
进行迭代,而是通过List
进行迭代。例如for(List l: getBatches(a)
。然后只需使getBatches()
返回ArrayList<List<Integer>>
通常,您会希望使用最抽象的东西。如果您不需要ArrayList
的实现特定细节,只需将其称为列表即可。
答案 2 :(得分:0)
这是使用raw type的结果。
通过调用new ArrayList(...)
而不指定T
的通用参数ArrayList<T>
,您使用的是原始类型ArrayList
。
上面链接的文档说:
但是,如果将原始类型分配给参数化类型,则会得到一个 警告:
Eclipse显示与new ArrayList(Arrays.asList(optionIds));
相关的以下警告:
类型安全:类型
ArrayList
的表达式无需检查 转换为符合ArrayList<ArrayList<Integer>>
因此,将原始类型的ArrayList
返回为ArrayList<ArrayList<Integer>>
不会导致编译时错误。
getBatches(a)
的结果为ArrayList<ArrayList<Integer>>
类型。此类型列表的元素的类型为ArrayList<Integer>
。使用原始类型ax
将它们分配给ArrayList
也不是编译时错误。
为了向后兼容,请将参数化类型分配给其原始数据 允许的类型:
但是在运行时,由于运行时类型为{{1},因此将getBatches(a)
的元素强制转换为ArrayList
时,忽略警告会导致ClassCastException
}无法强制转换为LinkedList
(目前已经具有已删除的通用类型)。