为什么我会获得类强制转换异常?

时间:2015-01-19 04:46:23

标签: java arrays list generics arraylist

我有两个类,AbstractArrayMyList类和一个ArrayListSorted类,它扩展了AbstractArrayMyList。

这是我对AbstractArrayMyList和相关构造函数的声明

public abstract class AbstractArrayMyList<E extends Comparable<E>> implements MyList<E>  {
    private static final int DEFAULT_CAPACITY = 100; 
    protected E[] elementData;
    public AbstractArrayMyList() {
            this( DEFAULT_CAPACITY);
    }
    public AbstractArrayMyList( int capacity) {
           elementData = (E[]) new Object[capacity];
    }

MyList是adt接口

我的ArrayListSorted类(带有相关的构造函数),

 public class ArrayListSorted<E extends Comparable<E>> extends 
       AbstractArrayMyList<E> {
       public ArrayListSorted() {
              super();
        }
}

以下是导致类强制转换异常的代码行。 (只是创建一个带有有界类型Integer的数组列表排序类。我真的很困惑为什么会发生这种异常。

ArrayListSorted<Integer> toTestInteger = new ArrayListSorted<Integer>();

chrylis从这里解释,Why am i getting a class cast exception(with generics, comparable)?问题是jvm将我的新Object [capacity]视为一个对象数组。我同意这一点,但那时我的AbstractArrayMyList的定义仍然是

public abstract class AbstractArrayMyList<E> implements MyList<E>   

,意味着jvm必须将E视为对象,因为它对此一无所知。但是因为我添加了E extends Comparable不应该允许这个演员吗? JVM会将其识别为可比较对象的数组吗?

2 个答案:

答案 0 :(得分:0)

如果JVM允许,你可以放置一个E以外的对象,比如 String ,当你检索对象时,你认为它是E并将它转换为E,这将导致ClassCastException在运行时。泛型完全阻止了这一点,在编译时检测尽可能多的失败。

答案 1 :(得分:0)

问题是对象不可比。因此,数组创建在Abstract类的构造函数中失败。

您可以通过删除抽象声明中的Comparable部分来解决问题:

 public abstract class AbstractArrayMyList<E> implements MyList<E>  {
   ...

}

然后在你的子类中:

public class ArrayListSorted<E extends Comparable<E>> extends AbstractArrayMyList<E> {
    ...
}

让一切顺利。没有类强制转换异常。

无论如何,这会更好,因为在您将AbstractArrayMyList的所有子类限制为Comparable之前。现在它不是必须的。

<强>更新

我现在明白你将在抽象类中使用元素。在这种情况下,请使您的数组类型为Comparable:

public abstract class AbstractArrayMyList<E extends Comparable<E>> implements List<E>  {

    ...

    public AbstractArrayMyList( int capacity) {
         elementData = (E[]) new Comparable[capacity];
   }

   ...

然后你的所有排序都会起作用:

例如,有一个主要方法:

public static void main(String... args){
    ArrayListSorted<Integer> toTestInteger = new ArrayListSorted<Integer>();

    toTestInteger.add(5);
    toTestInteger.add(2);
    System.out.println(toTestInteger.get(0));
    System.out.println(toTestInteger.get(1));

}

将正确打印

2
5

(这假设你的抽象类中的add()代码对数组进行了解析)

更新2

如果要在子类中进行排序,那么您将对抽象类进行一些小的更改。

使这项工作最简单的方法是使抽象类获取通过构造函数传入的数组。这样,子类就构成了数组的类型。

public abstract class AbstractArrayMyList<E> implements List<E>  {
    protected E[] elementData;
    int size=0;

    protected AbstractArrayMyList(E[] elementData) {
         this.elementData = elementData;
    }

    ....

 }

然后在你的子类中,你执行默认的容量,然后调用父的构造函数传递你已构造的正确类型的数组。

public class ArrayListSorted<E extends Comparable<E>> extends AbstractArrayMyList<E> {
     private static final int DEFAULT_CAPACITY = 100; 

     public ArrayListSorted(){
         this(DEFAULT_CAPACITY);
     }

     @SuppressWarnings("unchecked")
    public ArrayListSorted(int initialSize){
           //call parent constructor passing in new array
        super((E[]) new Comparable[initialSize]);
    }

...

现在代码再次按原样运行