【问题标题】:Java Collections ArrayList, LinkedList cast ExceptionJava 集合 ArrayList、LinkedList 强制转换异常
【发布时间】:2018-10-23 06:31:43
【问题描述】:

我发现了一个我至今无法解释的奇怪案例。

 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));
}

执行结果是:

线程“main”java.lang.ClassCastException 中的异常:java.util.LinkedList 无法转换为 java.util.ArrayList

for 循环中出现异常。

问题是:如何?返回类型为 ArrayList> 的方法如何返回 LinkedList?

【问题讨论】:

  • 您的getBatches 方法返回一个ArrayList,但是这个ArrayList 包含一个LinkedList。这就是您的循环失败的情况。

标签: java arraylist collections classcastexception


【解决方案1】:

你的方法返回一个原始的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相同的元素。

【讨论】:

    【解决方案2】:

    getBatches() 正在返回一个泛型类型为 ArrayList&lt;Integer&gt; 的 ArrayList。 Arrays.asList() 的返回类型是 List 接口。为了从 List 到 ArrayList 它正在执行隐式转换。这样做的问题是您不能直接将 ArrayList 转换为 LinkedList。

    解决这个问题相对简单。不是遍历ArrayLists,而是遍历Lists。例如for(List l: getBatches(a)。然后让getBatches()返回ArrayList&lt;List&lt;Integer&gt;&gt;

    一般来说,您会希望尽可能使用最抽象的东西。如果您不需要 ArrayList 的具体实现细节,只需将其称为 List。

    【讨论】:

      【解决方案3】:

      这是使用raw type的结果。

      通过调用new ArrayList(...) 而不指定ArrayList&lt;T&gt; 的泛型参数T,您使用的是原始类型ArrayList

      上面链接的文档说:

      但是,如果将原始类型分配给参数化类型,则会得到 警告:

      Eclipse 显示以下与new ArrayList(Arrays.asList(optionIds)); 相关的警告:

      类型安全:ArrayList 类型的表达式需要取消选中 转换为符合ArrayList&lt;ArrayList&lt;Integer&gt;&gt;

      因此,将原始类型的ArrayList 返回为ArrayList&lt;ArrayList&lt;Integer&gt;&gt; 不会导致编译时错误。

      getBatches(a) 的结果是ArrayList&lt;ArrayList&lt;Integer&gt;&gt; 类型。此类型化列表的元素类型为ArrayList&lt;Integer&gt;。使用原始类型 ArrayList 将它们分配给 ax 也不会出现编译时错误。

      为了向后兼容,将参数化类型分配给其原始 类型是允许的:

      但是在运行时,当涉及将getBatches(a) 的元素转换为ArrayList 时,忽略警告会导致ClassCastException,因为运行时类型LinkedList 不能转换为ArrayList (此时已经使用擦除的泛型类型)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-02
        • 1970-01-01
        • 2013-01-22
        • 1970-01-01
        • 1970-01-01
        • 2019-04-05
        • 2023-03-19
        • 2023-03-26
        相关资源
        最近更新 更多