我正在尝试实现排序和未排序的数组列表。两者都扩展了一个名为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
答案 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
的原因是编译器将方法签名替换为其删除,这基本上是可接受类型的最大公分母。由于您在子类中将E
从Object
缩小为Comparable
,因此该方法上的签名最终为Comparable[]
而不是Object[]
。< / p>