为什么我得到一个 class 转换异常(使用泛型,可比较)?

Why am i getting a class cast exception(with generics, comparable)?

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

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

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

我选择保护 elementData,以便排序和未排序的专用数组列表可以访问它并对其执行操作。这是我的 declaration/code 排序数组列表

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

我得到一个 class 转换异常

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 的 class 都必须实现 Comparable 接口...

我的意思是我什至拥有正确的语法,从 http://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html 开始,键入 extends class/interface

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

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

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

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