下面的代码在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 {}
}
答案 0 :(得分:6)
实际上,它是Java 8中的bug,在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)指出已解析的命名类,数组或接口类型。如果可以将object强制转换为已解析的类,数组或接口类型,则操作数堆栈不变。否则,checkcast指令将引发ClassCastException 。