访问Object[]类型的数组时发生ClassCastException 请考虑下面的java代码(我从现实世界中获取了它,但简化了一点,删除了无关的细节):
另一方面,如果我将显式强制转换添加到对象[],它将毫无例外地工作:访问Object[]类型的数组时发生ClassCastException 请考虑下面的java代码(我从现实世界中获取了它,但简化了一点,删除了无关的细节):,java,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&
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);
}
}
公共类问题{
@抑制警告(“未选中”)
私有T[]数据=(T[])新对象[1];
公共静态void main(最终字符串[]args){
最终CastIssue=新CastIssue();
System.out.println(((Object[])issue.data.length);
}
}
为什么在第一种情况下抛出异常
我使用JDK1.8.0(40
编辑:正如@wero所指出的,编译器在第一种情况下插入强制转换。我想了解为什么要在那里插入这个cast(很抱歉没有在原始问题中明确说明这一点)。对JLS或JVM规范的任何引用都是好的。在编译类中,由于类型擦除,字段
private T[]data
的类型是Object[]
。
但是当您访问它时(issue.data.length,在您的第一个示例中是
),它被强制转换为整数数组。使用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
由于类型擦除,
T
实际上是的非静态方法中的对象
。在main
方法中,T
已知为Integer
,因此问题.data
引用隐式转换为整数[]
整数[]
是对象[]
的子类,同样地整数
也是对象
的子类
可以将整数
分配给对象
类型的变量,但不能将对象
强制转换/分配给整数
类型的变量
数组也是如此:可以将整数[]
分配给对象[]
类型的变量,但不能将对象[]
强制转换/分配给整数[]
类型的变量
那么,如何使用泛型呢
为了让代码构造T
或T[]
的实际实例,必须为其提供运行时假定的T
的实际类
您可以在构造函数上传入该类,并使用反射创建数组:
private T[] data;
@SuppressWarnings("unchecked")
public CastIssue(Class<T> clazz) {
this.data = (T[])Array.newInstance(clazz, 1);
}
这样,主要方法就变成:
final CastIssue<Integer> issue = create(Integer.class);
System.out.println(issue.data.length);
final CastIssue=create(Integer.class);
System.out.println(issue.data.length);
这是否更好由您决定。父类型可以容纳子类型。。否则您必须执行显式类型转换!是的,我看到了演员阵容。我很想知道,当我访问数组的length属性时,为什么编译器会将它插入其中。最好参考一下JLS或JVM规范。我可能应该编辑我的问题,以便更明确地说明它。@AndrieiPolunin我相信我在回答的第一段中已经谈到了这一点,尽管没有提到JLS。希望有帮助。
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
private T[] data;
@SuppressWarnings("unchecked")
public CastIssue(Class<T> clazz) {
this.data = (T[])Array.newInstance(clazz, 1);
}
final CastIssue<Integer> issue = new CastIssue<Integer>(Integer.class);
System.out.println(issue.data.length);
public static <T> CastIssue<T> create(Class<T> clazz) {
return new CastIssue<T>(clazz);
}
final CastIssue<Integer> issue = create(Integer.class);
System.out.println(issue.data.length);