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

时间:2015-01-18 00:35:49

标签: java arrays generics interface comparable

我正在尝试实现排序和未排序的数组列表。两者都扩展了一个名为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扩展了Comparable,这意味着任何希望使用ArrayListSorted的类都必须实现Comparable接口......

我的意思是我甚至拥有正确的语法,来自http://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html,类型extends class / interface

1 个答案:

答案 0 :(得分:1)

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

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

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

您获得ClassCastException的原因是编译器将方法签名替换为其删除,这基本上是可接受类型的最大公分母。由于您在子类中将EObject缩小为Comparable,因此该方法上的签名最终为Comparable[]而不是Object[]。< / p>