ClassCastException对象无法强制转换为

时间:2014-06-08 08:10:08

标签: java generics classcastexception

我不明白为什么我会在下面的代码中获得 ClassCastException

for(int i = 0; i < k.t.length; i++)

问题是在方法addElement中我用类型为T的对象替换数组元素。在我看来,数组应该是类型为T的对象。编译器并没有为此提出抗议。 但是在运行时JVM无法转换,尽管在数组中实际上是类型为T的对象(如果在String下面),为什么JVM不能使用多态?

但是当我将T[] t;更改为Object[] t;

并删除构造函数中的强制转换,它运行正常,没有任何错误,为什么?

public class MyCollection<T> {

T[] t;

MyCollection( int size){
    t = (T[]) new Object[size];
}

boolean addElement(T e, int i){        
    if(i < t.length){
        t[i] = e;
        return true;
    }
    return false;

}


public static void main(String[] ss){

    MyCollection<String> k = new MyCollection<String>(3);

    k.addElement("a",0);
    k.addElement("b",1);
    k.addElement("c",2);

    for(int i = 0; i < k.t.length; i++)
        System.out.println(k.t[i]);     

    //for(String s : (String[])k.t)
    //    System.out.println(s);        
 }
}

3 个答案:

答案 0 :(得分:4)

问题是你正在向Object[]投射T[],然后你暴露了底层数组。这完全有效的唯一原因是因为T的类型擦除是Object。但由于在我们的情况下T被解释为String,当我们从外部访问数组时,我们会尝试将其强制转换为String[],这是不正确的。为了避免此问题,您应该将数组设为私有,并提供访问器方法来检索元素。通过这样做,您只需将单个元素转换为正确的类型,而无需对底层数组进行假设。

public class MyCollection<T> {

    private T[] t;

    MyCollection( int size){
        t = (T[]) new Object[size];
    }

    boolean addElement(T e, int i){        
        if(i < t.length){
            t[i] = e;
            return true;
        }
        return false;

    }

    T getElement(int index) {
        return t[index];
    }

    int getLength() {
        return t.length;
    }

    public static void main(String[] ss){

        MyCollection<String> k = new MyCollection<String>(3);

        k.addElement("a",0);
        k.addElement("b",1);
        k.addElement("c",2);

        for(int i = 0; i < k.getLength(); i++)
            System.out.println(k.getElement(i));     

        //for(String s : (String[])k.t)
        //    System.out.println(s);        
     }
}

请注意,Java的Collection接口演示了相同的行为。无论Object[]的类型如何,Collection.toArray()都会返回E。唯一可用的解决方法是Collection.toArray(T[]),您必须在其中传递具有固定类型的数组,然后可以填充或复制该数组。

答案 1 :(得分:1)

再次检查问题的界限。在我看来,由于以下原因将抛出异常:

    for(String s : (String[])k.t)

你在这里试图转换为String [],而数组被定义为Object []:

t = (T[]) new Object[size];

答案 2 :(得分:0)

您可以使用反射创建一个新的数组实例,以避免ClassCastException

示例:

    import java.lang.reflect.Array;

public class MyCollection<T> {

    T[] t;

    MyCollection(Class<T> clazz, int size) {
        t = (T[]) Array.newInstance(clazz, size);

    }

    boolean addElement(T e, int i) {
        if (i < t.length - 1) {
            t[i] = e;
            return true;
        }
        return false;

    }

    public static void main(String[] ss) {

        MyCollection<String> k = new MyCollection<String>(String.class, 3);

        k.addElement("a", 0);
        k.addElement("b", 1);
        k.addElement("c", 2);

        for (int i = 0; i < k.t.length; i++)
            System.out.println(k.t[0]);

    }
}