【问题标题】:Why am i getting a class cast exception(with generics, comparable)?为什么我得到一个类转换异常(具有泛型,可比较)?
【发布时间】:2015-01-18 00:35:49
【问题描述】:

我正在尝试实现已排序和未排序的数组列表。两者都扩展了一个名为 AbstractArrayMyList 的类,其中包含常见的操作/实现 - toString、clear 等......

这是我的 AbstractArrayMyList 代码(它实现了我定义的通用接口)

public abstract class AbstractArrayMyList<E> implements MyList<E> {
        protected E[] elementData;
       .....
}

我选择对 elementData 进行保护,以便已排序和未排序的专用数组列表可以访问并对其执行操作。这是我的排序数组列表的声明/代码

public class ArrayListSorted<E extends Comparable<E>> extends AbstractArrayMyList<E> 

这一切都编译得很好。但是,当我用这些行测试我的代码时

ArrayListSorted<Integer> toTestInteger = new ArrayListSorted<Integer>()
toTestInteger.insert(0);
assertEquals(toTestInteger.get(0).intValue(), 0);

我得到一个类转换异常

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
    at myarraylist.ArrayListSorted.getIndex(ArrayListSorted.java:38)

发生在这里

@Override
public int getIndex(E value) {
     int lo = 0;
     int hi = size;
     while (lo <= hi) {
         // Key is in a[lo..hi] or not present.
         int mid = lo + (hi - lo) / 2;
         if      (value.compareTo(elementData[mid]) < 0)  hi = mid - 1;

该异常与 compareTo 发生在同一行。有谁知道问题是什么?我定义了有界通配符,E extends Comparable,这意味着任何希望使用 ArrayListSorted 的类都必须实现 Comparable 接口...

我的意思是我什至有正确的语法,从http://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html,类型扩展类/接口

【问题讨论】:

    标签: java arrays generics interface comparable


    【解决方案1】:

    问题是您使用泛型类型作为数组的类型。数组类型在运行时被reified(实际上存在于 JVM 中),但泛型类型不是。这意味着您的 new E[] 实际上最终会成为 Object[] 而不是您想要的类型的数组。

    标准集合通过不提供对数组的直接访问并在get() 等操作上强制转换为E 来解决此问题。如果你真的认为使用类型化数组是最好的选择,那么你需要将Class&lt;E&gt; clazz 传递给抽象基类的构造函数,并使用它来构造一个类型正确的数组:

    protected AbstractArrayMyList(Class<E> clazz) {
        this.elementClass = clazz;
        this.elementData = Array.newInstance(clazz, INITIAL_SIZE);
    }
    

    你得到ClassCastException 的原因是编译器用它们的擦除替换了方法签名,这基本上是可接受类型的最大公分母。由于您在子类中将 EObject 缩小到 Comparable,因此该方法上的签名最终是 Comparable[] 而不是 Object[]

    【讨论】:

    • 所以投到可比?还是在排序后的数组列表中重新初始化?
    • @committedandroider 按照我上面说的做:将E 传递给超类构造函数,并首先使用它来创建数组。
    • 从这里,“如果你真的认为使用类型化数组是最好的选择”,你是否暗示有更好的方法来做到这一点?
    • @committedandroider ...您阅读我的回答了吗?我解释了标准集合类如何处理打字问题。
    • 对不起,我真的很困惑。所以在这行代码中,当我初始化 elementData, elementData = (E[]) new Object[capacity] 时,你的意思是它最终还是一个对象数组?
    猜你喜欢
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-11
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多