奇怪的运行时错误(声明时ClassCastException) [英] Weird runtime error (ClassCastException while declaring)

查看:126
本文介绍了奇怪的运行时错误(声明时ClassCastException)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写的程序中包含以下代码:

I have the following code within a program I'm making:

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 ,出现此错误:

but when I run method methodA, I get this error:

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 在检查其长度时不会为空),但是我相信我已经展示了所有重要的内容。为什么不运行呢?

Why would I get this error? Of course, the code I've shown is incomplete compared to the huge class in question (for instance, the array t won't be empty when checking its length), but I believe I've shown everything that matters. Why won't this run?

注意:我正在使用JDK 1.7进行此操作,因此这就是第7行能够编译和运行的原因

A note: I am making this with JDK 1.7, so that's why line 7 compiles and works

出于任何原因,我决定实施

I decided, for whatever reason, to implement the following solution, and it worked:

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  }

尽管这是一个解决方案,但我仍然会想知道它为什么工作。

Though this is a solution, I would still like to know why it works.

推荐答案

您缺少初始化 T ,但我将假定它看起来像这样。我添加了几行,不会更改任何功能,但可以帮助说明错误:

You are missing the code that initializes T, but I'm going to assume it looks something like this. I've added a few lines that don't change any functionality but which will help demonstrate the error:

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);
    }
}

使用此代码,我可以重现该错误。问题出在此代码中:

With this code I could reproduce the error. The problem here is in this code:

int l2 = ints2.t.length

由于编译器知道 ints2 的类型参数,因此也知道 ints2 .t ,可以这样认为:

Since the compiler knows the type parameter for ints2 and thus ints2.t, this can be thought of as the rough equivalent of this:

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

它是隐式转换为 Integer [] (其类的简单名称为 [Ljava.lang.Integer )),因为 t Object [] 而不是 Integer [] ,并且一个不能转换为另一个。

It is in the implicit cast to Integer[] (whose class simple name is [Ljava.lang.Integer) that this fails, since t is an Object[] and not an Integer[], and one cannot be cast to the other.

使用在通用类型上声明的数组会带来很多麻烦,这些在其他地方都有介绍。简而言之,我要说的是,如果您需要一个通用数组,而不是考虑以各种方式将其声明为 Object [] 并将其用作 ,当您与该类的客户进行交互时,您只接受或返回 T 而不是 Object (用于返回,通过未检查的强制转换)。例如,

There are many complications from working with arrays declared over a generic type that are documented elsewhere. In short, I'll say that if you need to have a "generic array" instead consider declaring and using it as an Object[] in every way, except that when you interact with a client of the class, you either accept or return only a T instead of an Object (for returning, via an unchecked cast). For example,

Object[] t = new Object[5];

public T getSomethingFromArray() {
    return (T)t[2];
}

public void setSomethingInArray(T something) {
    t[2] = something;
}

ArrayList 顺便说一句。看看其在DocJar上的代码

This is how ArrayList works, by the way. Have a look at its code on DocJar.

除了通用数组,我认为您不理解隐式强制转换的想法。以下是简短得多的代码,但失败的原因基本上是相同的错误:

Generic arrays aside, I don't think you understand the idea of the implicit cast. Here's much shorter code that fails with essentially the same error:

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 输出:

Even though there is no need to cast clazz.t to a String, it does so implicitly simply by referencing clazz.t. Here is the javap -c output for that compiled class:

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

}

对于您的原始代码,这是 methodA() javap -c 输出:

In the case of your original code, here is the javap -c output of methodA():

public Clazz methodA(int[]);
  Code:
   0:   new #5; //class Clazz
   3:   dup
   4:   invokespecial   #6; //Method "<init>":()V
   7:   astore_2
   8:   aload_0
   9:   getfield    #4; //Field t:[Ljava/lang/Object;
   12:  arraylength
   13:  aload_2
   14:  getfield    #4; //Field t:[Ljava/lang/Object;
//BELOW is the line that will fail
   17:  checkcast   #7; //class "[Ljava/lang/Integer;"
   20:  arraylength
   21:  isub
   22:  newarray int
   24:  astore_3
   25:  aload_0
   26:  areturn

这篇关于奇怪的运行时错误(声明时ClassCastException)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆