奇怪的运行时错误(声明时ClassCastException)

时间:2011-06-30 16:32:56

标签: java classcastexception

我正在制作的程序中有以下代码:

01  public class Clazz<T>
02  {
03    T[] t;
04    
05    public Clazz<T> methodA(int... ints)
06    {
07      Clazz<Integer> ints2 = new Clazz<>();
08      int remInd[] = new int[t.length - ints2.t.length];
09      return this;
10    }
11  }

但是当我运行方法methodA时,我收到此错误:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
    at Clazz.methodA(Clazz.java:8)

为什么我会收到此错误?当然,我所展示的代码与所讨论的巨大类相比是不完整的(例如,数组t在检查其长度时不会为空),但我相信我已经展示了一切重要的东西。为什么不运行?

注意:我正在使用JDK 1.7进行此操作,因此第7行编译并正常工作

工作解决方案


无论出于何种原因,我决定实施以下解决方案,并且有效:

01  public class Clazz<T>
02  {
03    T[] t;
04    
05    public Clazz<T> methodA(int... ints)
06    {
07      Clazz<Integer> ints2 = new Clazz<>();
08      int remInd[] = new int[t.length - ints2.length()];
09      return this;
10    }
11    
12    public int length()
13    {
14      return t.length;
15    }
16  }

虽然这是一个解决方案,但我仍然想知道它的工作原理。

1 个答案:

答案 0 :(得分:7)

您缺少初始化T的代码,但我会假设它看起来像这样。我添加了几行不会改变任何功能但有助于演示错误的行:

public class Clazz<T> {
    T[] t = (T[]) new Object[5];

    public Clazz<T> methodA(int... ints) {
        Clazz<Integer> ints2 = new Clazz<Integer>();
        int l1 = t.length;
        int l2 = ints2.t.length;
        int remInd[] = new int[l1 - l2];
        return this;
    }

    public static void main(String...args) {
        Clazz<String> clazz = new Clazz<String>();
        clazz.methodA(54, 7);
    }
}

使用此代码我可以重现错误。这里的问题在于此代码:

int l2 = ints2.t.length

由于编译器知道ints2的类型参数,因此知道ints2.t,因此可以将其视为粗略的等价物:

Integer[] temp = ints2.t;
int l2 = temp.length;

由于Integer[][Ljava.lang.Integer而不是{{1},因此t(其类名称为Object[])的隐式强制转换失败了一个人不能被投射到另一个人身上。

使用通用数组

使用在其他地方记录的泛型类型声明的数组有许多复杂情况。简而言之,我会说,如果你需要一个“通用数组”,而是考虑在各方面声明并将其用作Integer[]除了,当你与客户交互时在该类中,您只接受或仅返回Object[]而不是T(通过未经检查的演员表返回)。例如,

Object

顺便说一下Object[] t = new Object[5]; public T getSomethingFromArray() { return (T)t[2]; } public void setSomethingInArray(T something) { t[2] = something; } 的工作原理。看看its code on DocJar

修改

除了通用数组之外,我认为你不理解隐式转换的想法。这是更短的代码,失败的基本相同的错误:

ArrayList

即使不需要将public class Clazz<T> { T t = (T) new Object(); public static void main(String...args) { Clazz<String> clazz = new Clazz<String>(); clazz.t.toString(); } } Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String at Clazz.main(Clazz.java:6) ... 强制转换为字符串,也只需通过引用 clazz.t隐式。以下是该编译类的clazz.t输出:

javap -c

对于原始代码,此处为Compiled from "Clazz.java" public class Clazz extends java.lang.Object{ java.lang.Object t; public Clazz(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: new #2; //class java/lang/Object 8: dup 9: invokespecial #1; //Method java/lang/Object."<init>":()V 12: putfield #3; //Field t:Ljava/lang/Object; 15: return public static void main(java.lang.String[]); Code: 0: new #4; //class Clazz 3: dup 4: invokespecial #5; //Method "<init>":()V 7: astore_1 8: aload_1 9: getfield #3; //Field t:Ljava/lang/Object; //BELOW is the line that will fail 12: checkcast #6; //class java/lang/String 15: invokevirtual #7; //Method java/lang/String.toString:()Ljava/lang/String; 18: pop 19: return } 的{​​{1}}输出:

javap -c