我试图实现一个排序和未排序的数组列表。两者都扩展了一个名为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,类型扩展了类/接口
问题是您将泛型类型用作数组的类型。在运行时对数组类型进行了 修饰 (实际上存在于JVM中),但没有对通用类型进行修饰。这意味着您new E[]实际上最终将成为Object[]所需类型的数组,而不是该数组。
new E[]
Object[]
标准集合通过不提供直接访问数组和强制转换为Eon等操作来解决此问题get()。如果您真的认为使用类型化数组是最好的选择,那么您将需要传递Class<E> clazz给抽象基类的构造函数,并使用它来构造一个正确类型化的数组:
E
get()
Class<E> clazz
protected AbstractArrayMyList(Class<E> clazz) { this.elementClass = clazz; this.elementData = Array.newInstance(clazz, INITIAL_SIZE); }
您得到的原因ClassCastException是,编译器将其签名替换为擦除,这基本上是可接受类型的最大公分母。由于您要缩小子类中的E从Object到Comparable,因此该方法上的签名最终被Comparable[]代替Object[]。
ClassCastException
Object
Comparable
Comparable[]