java - 为什么这个带有泛型的代码会在 Java 11 中引发 ClassCastException?

标签 java generics

下面的代码在 Java 8 中成功,但在 Java 11 中抛出 ClassCastException。为什么行为会发生变化?

我在 OpenJDK 的 Java 9、Java 10 或 Java 11 功能集中找不到任何相关更改。

public class GenericsExample {

    public static void main(String[] args) {
        Set<Car> set = new HashSet<>();
        set.add(getAnimal());
    }

    static <T extends Animal> T getAnimal() {
        return (T) new Animal() {};
    }

    interface Animal {}

    class Car {}
}

最佳答案

确实是 bug在 Java 8 中,已在 Java 9 中修复 - bugfix .
在某些情况下,javac CHECKCAST指令被跳过。

如果您好奇,请考虑以下两行代码:

Set<Car> set = new HashSet<>(); // line 11
set.add(getAnimal());           // line 12

Java 8 字节码将如下所示:
 LINENUMBER 11 L1
 ALOAD 1
 ALOAD 0
 INVOKEVIRTUAL UserManagerTest.getAnimal ()LUserManagerTest$Animal;
 INVOKEINTERFACE java/util/Set.add (Ljava/lang/Object;)Z (itf)
 POP

但是 Java 9 看起来像这样:
LINENUMBER 11 L1
ALOAD 1
ALOAD 0
INVOKEVIRTUAL UserManagerTest.getAnimal ()LUserManagerTest$Animal;
CHECKCAST UserManagerTest$Car
INVOKEINTERFACE java/util/Set.add (Ljava/lang/Object;)Z (itf)
POP

唯一的区别是 CHECKCAST指令,(根据 JavaDoc )声明命名的类、数组或接口(interface)类型已解析。如果 object 可以转换为已解析的类、数组或接口(interface)类型,则操作数堆栈不变;否则,checkcast 指令会抛出 ClassCastException。

关于java - 为什么这个带有泛型的代码会在 Java 11 中引发 ClassCastException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54334575/

相关文章:

javascript - 从 Java 实例变量存储 Javascript 函数

在两种类型之间进行转换的 Java 通用实用方法

node.js - 如何在 typescript 中创建泛型类型参数的实例

java - 可以将泛型添加到 Java 中非泛型接口(interface)的实现中吗?

c# - 具有类约束的字段

java - 关于 Android 上存储的快速问题

java - 加载包 org.renjin.cran 时出现 IOException :rgeos: Could not resolve native method 'rgeos_Init' in package 'rgeos'

Java - 无法加密 RDP 文件中的 Windows 远程桌面密码

java - 具有 Redshift 设置的 QueryDSL

java 工厂方法和泛型