Java泛型:为什么这个输出成为可能?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (17)

我有这个班级:

class MyClass<N extends Number> {
    N n = (N) (new Integer(8));
}

我想获得这些输出:

System.out.println(new MyClass<Long>().n);
System.out.println(new MyClass<Long>().n.getClass());
  1. 第一条System.out.println()语句的输出: 8
  2. 第二个System.out.println()陈述的输出: java.lang.ClassCastException: java.lang.Integer (in module: java.base) cannot be cast to java.lang.Long (in module: java.base)

为什么我会得到第一个输出?是不是也有演员?为什么我会在第二个输出中得到异常?

PS:我使用Java 9; 我用JShell试了一下,两个输出都有异常。然后,我用IntelliJ IDE试了一下,得到了第一个输出,但第二个输出了异常。

提问于
用户回答回答于

IntelliJ显示的行为对我来说很清楚:

你有一个未经检查的演员MyClass。这意味着new Integer(8)不会立即投射到Long擦除Number(工作),而是执行此行时:N n =(N)(new Integer(8));

现在让我们看看输出语句:

System.out.println(new MyClass<Long>().n);

归结为String.valueOf(new MyClass<Long>().n)- > ((Object)new MyClass<Long>().n).toString()哪些工作正常,因为n是通过访问Object,也toString()通过静态类型访问的方法Object- >没有强制转换Long发生。new MyClass<Long>().n.toString()会因为例外而失败,因为toString()试图通过静态类型进行访问Long。因此,Long发生n型转换是不可能的(Integer不能转换为Long)。

执行第二条语句时会发生同样的情况:

System.out.println(new MyClass<Long>().n.getClass()); 

尝试通过静态类型访问类型中getClass声明的方法。因此,发生n到类型的转换会产生一个转换异常。ObjectLongLongLong

JShell的行为:

我试图重现JShell上的第一个输出语句的异常 - Java 9早期访问版本151:

jshell> class MyClass<N extends Number> {
   ...>     N n = (N) (new Integer(8));
   ...> }
|  Warning:
|  unchecked cast
|    required: N
|    found:    java.lang.Integer
|      N n = (N) (new Integer(8));
|                ^--------------^
|  created class MyClass

jshell> System.out.println(new MyClass<Long>().n);
8

jshell> System.out.println(new MyClass<Long>().n.getClass());
|  java.lang.ClassCastException thrown: java.base/java.lang.Integer cannot be cast to java.base/java.lang.Long
|        at (#4:1)

但似乎JShell与IntelliJ的结果完全相同。System.out.println(new MyClass<Long>().n);输出8 - 没有例外。

用户回答回答于

这是因为Java擦除而发生的。

Integer扩展以来Number,编译器接受转换N。在运行时,由于(由于擦除)N被替换,Number存储Integer内部没有问题n

方法的参数System.out.println是类型的,Object所以打印的值不存在问题n

但是,在调用方法时n,编译器将添加类型检查以确保调用正确的方法。因此导致a ClassCastException

扫码关注云+社区