为什么我得到一个 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 中将 E
从 Object
缩小到 Comparable
,因此该方法的签名最终是 Comparable[]
而不是 Object[]
.
我正在尝试实现排序和未排序的数组列表。两者都扩展了一个名为 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 中将 E
从 Object
缩小到 Comparable
,因此该方法的签名最终是 Comparable[]
而不是 Object[]
.