简体   繁体   English

访问Object []类型的数组时发生ClassCastException

[英]ClassCastException when accessing array of type Object[]

Please consider the following piece of Java code (I have taken it from real world but simplified a bit and removed irrelevant details): 请考虑以下Java代码(我从真实世界中获取了该代码,但做了一些简化,并删除了无关的细节):

public class CastIssue<T> {
  @SuppressWarnings("unchecked")
  private T[] data = (T[]) new Object[1];

  public static void main(final String[] args) {
    final CastIssue<Integer> issue = new CastIssue<>();
    System.out.println(issue.data.length);
  }
}

It compiles fine but throws the following exception when executed: 它可以很好地编译,但是在执行时抛出以下异常:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
    at CastIssue.main(CastIssue.java:7)

On the other hand if I add explicit cast to Object[] it works without exception: 另一方面,如果我向Object []添加显式强制转换,则可以正常工作:

public class CastIssue<T> {
  @SuppressWarnings("unchecked")
  private T[] data = (T[]) new Object[1];

  public static void main(final String[] args) {
    final CastIssue<Integer> issue = new CastIssue<>();
    System.out.println(((Object[])issue.data).length);
  }
}

Why does exception is thrown in the first case? 为什么在第一种情况下会引发异常?

I use JDK 1.8.0_40 我使用JDK 1.8.0_40

EDIT: as noted by @wero, compiler inserts a cast in the first case. 编辑:@wero指出,编译器在第一种情况下会插入强制类型转换。 I want to understand why that cast is inserted there (sorry for not stating this explicitly in the original question). 我想了解为什么将演员表插入那里(很抱歉,在原始问题中未明确说明)。 Any references to JLS or JVM specification would be good. 任何对JLS或JVM规范的引用都可以。

In the compiled class the type of the field private T[] data is Object[] due to type erasure. 在已编译的类中,由于类型擦除,字段private T[] dataObject[] But when you access it ( issue.data.length in your first example) it is casted to a Integer array. 但是,当您访问它时(第一个示例中的issue.data.length ),它被issue.data.length转换为Integer数组。 This is easy to see when you decompile the class with javap : 使用javap反编译类时,这很容易看到:

  public static void main(java.lang.String[]);
    Code:
       0: new           #1                  // class test/CastIssue
       3: dup
       4: invokespecial #24                 // Method "<init>":()V
       7: astore_1
       8: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
      11: aload_1
      12: getfield      #14                 // Field data:[Ljava/lang/Object;
      15: checkcast     #31                 // class "[Ljava/lang/Integer;"
      18: arraylength
      19: invokevirtual #33                 // Method java/io/PrintStream.println:(I)V
      22: return

When you cast it to an Object array (your second example), the checkcast operation is dropped and the error does not occur: 当您将其checkcast转换为Object数组(第二个示例)时, checkcast操作将被丢弃,并且不会发生错误:

  public static void main(java.lang.String[]);
    Code:
       0: new           #1                  // class test/CastIssue
       3: dup
       4: invokespecial #24                 // Method "<init>":()V
       7: astore_1
       8: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
      11: aload_1
      12: getfield      #14                 // Field data:[Ljava/lang/Object;
      15: arraylength
      16: invokevirtual #31                 // Method java/io/PrintStream.println:(I)V
      19: return    

Because of type erasure, T is actually an Object in the non-static methods of CastIssue . 由于类型擦除,在CastIssue的非静态方法中T实际上是一个Object In the main method, T is known to be Integer , so the issue.data reference is implicitly cast to an Integer[] . main方法中,已知TInteger ,因此issue.data参考隐式转换为Integer[]

An Integer[] is a subclass of an Object[] , in the same way Integer is a subclass of an Object . Integer[]Object[]的子类,就像IntegerObject的子类一样。

You can assign an Integer to a variable of type Object , but you cannot cast/assign an Object to a variable of type Integer . 您可以将Integer分配给Object类型的变量,但是不能将Object强制转换/分配给Integer类型的变量。

Same goes for the arrays: You can assign an Integer[] to a variable of type Object[] , but you cannot cast/assign an Object[] to a variable of type Integer[] . 数组也是如此:您可以将Integer[]分配给Object[]类型的变量,但是不能将Object[]强制转换/分配给Integer[]类型的变量。


So, how do you do it, with generics? 那么,如何使用泛型呢?

In order for the code to construct an actual instance of T , or a T[] , it must be given the actual Class of whatever T is supposed to be at runtime. 为了使代码构造TT[]的实际实例,必须为它在运行时赋予T的实际Class

You can pass in that class on the constructor, and use reflection to create the array: 您可以在构造函数上传递该类,并使用反射来创建数组:

private T[] data;

@SuppressWarnings("unchecked")
public CastIssue(Class<T> clazz) {
    this.data = (T[])Array.newInstance(clazz, 1);
}

Your main method will then be: 您的主要方法将是:

final CastIssue<Integer> issue = new CastIssue<Integer>(Integer.class);
System.out.println(issue.data.length);

Specifying Integer twice on the constructor seems redundant, and sure it can be collapsed with the diamond operator ( new CastIssue<>(Integer.class) ), but still... 在构造函数上两次指定Integer似乎是多余的,并且确保可以使用菱形运算符( new CastIssue<>(Integer.class) )将其折叠,但是仍然...

You can use a generic static method to let the compiler infer the type ( T ) from the parameter: 您可以使用通用静态方法让编译器从参数推断类型( T ):

public static <T> CastIssue<T> create(Class<T> clazz) {
    return new CastIssue<T>(clazz);
}

This way the main method becomes: 这样,主要方法变为:

final CastIssue<Integer> issue = create(Integer.class);
System.out.println(issue.data.length);

Whether that's better is for you to decide. 是否更好取决于您的决定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java中将Object []数组转换为泛型类型数组时发生ClassCastException - ClassCastException when casting Object[] array to generic type array in Java 强制转换为对象数组时发生ClassCastException - ClassCastException when casting to object array 将对象Array转换为Long数组时出现ClassCastException - ClassCastException when casting object Array to Long array java.lang.ClassCastException-访问对象数组的Java数组,例如二维对象数组 - java.lang.ClassCastException - Accessing Java array of Object arrays like 2 dimensional object array 尝试创建内部类类型的数组时获取ClassCastException - Getting ClassCastException when trying to create an array of an inner class type 尝试创建具有类型变量的类的数组时发生ClassCastException - ClassCastException when trying to create an array of a class with type variables 强制转换为同一对象时发生ClassCastException - ClassCastException when casting to same object 当`ScriptEngine`的case对象时,`ClassCastException` - `ClassCastException` when case object with `ScriptEngine` 附加对象OutputStream时的ClassCastException - ClassCastException when Appending Object OutputStream 将数组强制转换为readObject时发生ClassCastException - ClassCastException when casting array to readObject
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM