为什么这段带有泛型的代码在Java11中抛出ClassCastException?
下面的代码在Java8中成功,但在Java11中抛出ClassCastException。为什么行为会改变 我在OpenJDK的Java9、Java10或Java11特性集中找不到任何相关的更改为什么这段带有泛型的代码在Java11中抛出ClassCastException?,java,generics,Java,Generics,下面的代码在Java8中成功,但在Java11中抛出ClassCastException。为什么行为会改变 我在OpenJDK的Java9、Java10或Java11特性集中找不到任何相关的更改 public class GenericsExample { public static void main(String[] args) { Set<Car> set = new HashSet<>(); set.add(getAnim
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 {}
}
公共类泛型示例{
公共静态void main(字符串[]args){
Set=newhashset();
set.add(getAnimal());
}
静态T getAnimal(){
返回(T)新动物(){};
}
界面动物{}
类车{}
}
事实上,它在Java8中是一个错误,在Java9中是固定的。
在某些场景中,跳过了javacCHECKCAST
指令
如果你很好奇,就考虑这2行代码:
Set<Car> set = new HashSet<>(); // line 11
set.add(getAnimal()); // line 12
但Java 9将如下所示:
LINENUMBER 11 L1
ALOAD 1
ALOAD 0
INVOKEVIRTUAL UserManagerTest.getAnimal ()LUserManagerTest$Animal;
INVOKEINTERFACE java/util/Set.add (Ljava/lang/Object;)Z (itf)
POP
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
指令,它(根据)声明已解析命名的类、数组或接口类型。如果对象可以转换为解析的类、数组或接口类型,则操作数堆栈不变;否则,checkcast指令将抛出ClassCastException。您正试图将Animal添加到汽车集合中。。。这是怎么回事?O.oNote指出,这种仅返回类型的通用参数需要非常小心地使用,另请参见。当涉及交叉类型和有界泛型参数时,有几个与类型推断相关的错误。据我所知,强制转换的getAnimal()
从未转换为运行时检查-擦除后,如果我没有弄错的话,这只是static Animal getAnimal()
,编译器接受它是因为Animal
是一个接口,可能有一个Car
也是Animal
,因此它推断T
是Car
和Animal
的连接类型,它编译得很好-但它应该生成一个运行时检查来验证这一点。我觉得有些版本无法在调用站点插入此运行时检查。如果Animal
是一个类,则在我测试的所有版本中编译都会失败。另外请注意,如果您确实知道自己在做什么,这是一个很好的参数,可以仅禁止或忽略“unchecked cast”警告-return(T)new Animal(){
会导致这样的警告,因为编译器无法保证您的Animal
的匿名子类型确实是T