Java泛型:为什么这种输出是可能的?

2022-08-31 20:39:00

我有这个类:

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尝试了它,并得到了第一个输出,但第二个输出异常。


答案 1

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

您在 中有一个未经检查的转换。这意味着在执行此行时,不会立即强制到擦除(有效)中:MyClassnew Integer(8)LongNumberN n =(N)(new Integer(8));

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

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

归结为 -> 这工作正常,因为 n 是通过访问的,并且该方法也是通过静态类型 ->不会发生强制转换。 将失败并显示异常,因为 尝试通过静态类型 访问 。因此,发生 n 到类型的强制转换是不可能的(不能强制转换为 )。String.valueOf(new MyClass<Long>().n)((Object)new MyClass<Long>().n).toString()ObjecttoString()ObjectLongnew MyClass<Long>().n.toString()toString()LongLongIntegerLong

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

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

尝试通过静态类型 访问类型的方法(在 中声明)。因此,发生 n 到类型的强制转换,从而产生强制转换异常。getClassObjectLongLongLong

JShell 行为:

我试图重现JShell上第一个输出语句的结果异常 - Java 9早期访问Build 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完全相同的结果。 产出8 - 无一例外。System.out.println(new MyClass<Long>().n);


答案 2

发生这种情况是因为Java擦除。

由于 extends,编译器接受强制转换为 。在运行时,由于被替换为(由于擦除),因此存储内部没有问题。IntegerNumberNNNumberIntegern

方法的参数是类型,因此打印 的值没有问题。System.out.printlnObjectn

但是,当调用 on 上的方法时,编译器会添加类型检查,以确保调用正确的方法。因此,产生 .nClassCastException


推荐