为什么我会得到一个类强制转换exception(使用generics,可比较)?
我正在尝试实现一个排序和未排序的数组列表。 两者都扩展了一个名为AbstractArrayMyList的类,它包含常见的操作/实现 – toString,clear等….
这是我的AbstractArrayMyList代码(它实现了我定义的通用接口)
public abstract class AbstractArrayMyList implements MyList { protected E[] elementData; ..... }
我选择对elementData进行保护,以便排序和未排序的专用数组列表可以访问它并对其执行操作。 这是我的排序数组列表的声明/代码
public class ArrayListSorted<E extends Comparable> extends AbstractArrayMyList
这一切都很好。 但是当我用这些行测试我的代码时
ArrayListSorted toTestInteger = new ArrayListSorted() toTestInteger.insert(0); assertEquals(toTestInteger.get(0).intValue(), 0);
我得到一个类强制转换exception
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;
该exception发生在与compareTo相同的行上。 有谁知道这是什么问题? 我定义了有界通配符,E扩展了Comparable,这意味着任何希望使用ArrayListSorted的类都必须实现Comparable接口…
我的意思是我甚至有正确的语法,来自http://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html ,输入extends class / interface
问题是您使用generics类型作为数组的类型。 数组类型在运行时被实现(实际存在于JVM中),但generics类型不是。 这意味着您的new E[]
实际上最终成为Object[]
而不是您想要的类型的数组。
标准集合通过不提供对数组的直接访问并在get()
类的操作上转换为E
来解决此问题。 如果您真的认为使用类型化数组是最佳选择,那么您需要将Class
传递给抽象基类的构造函数,并使用它来构造正确类型的数组:
protected AbstractArrayMyList(Class clazz) { this.elementClass = clazz; this.elementData = Array.newInstance(clazz, INITIAL_SIZE); }
你得到ClassCastException
的原因是编译器用它们的擦除替换方法签名,这基本上是可接受类型的最大公分母。 由于您在子类中将E
从Object
缩小为Comparable
,因此该方法上的签名最终为Comparable[]
而不是Object[]
。