当使用HashMap时,Java11中的ClassCastException而不是Java8中的ClassCastException?

当使用HashMap时,Java11中的ClassCastException而不是Java8中的ClassCastException?,java,generics,java-8,hashmap,java-11,Java,Generics,Java 8,Hashmap,Java 11,请看一下我的代码: Object longL = 2548214; Map<String, Object> map = new HashMap<String, Object>(1); map.put("LongNumber", longL); List<Map<String, Object>> returnlist = new ArrayList(10); returnlist.add(map); List<Object> versi

请看一下我的代码:

Object longL = 2548214;
Map<String, Object> map = new HashMap<String, Object>(1);
map.put("LongNumber", longL);
List<Map<String, Object>> returnlist = new ArrayList(10);
returnlist.add(map);

List<Object> versionMap1 = new ArrayList(10);
versionMap1.add(returnlist);

List<Map<String, String>> docIdVersionNameMap = new ArrayList<>();
docIdVersionNameMap.addAll((List<Map<String, String>>)versionMap1.get(0));

Map<String, String> versionDoc=docIdVersionNameMap.get(0);

Map<String,String> versionDocInfo=new HashMap<String,String>(1);
versionDocInfo.put(versionDoc.get("LongNumber"),"abc");
System.out.println(versionDocInfo.toString());

Java 11中是否有关于HashMap的任何更改?

抛出的
ClassCastException
是正确的。没有抛出它是由
javac
中的一个bug引起的,该bug在JDK 9中由修复。从技术上讲,您的代码依赖于堆污染不会被拾取,因此它永远不能保证不会被破坏

基本上,在Java11中(但从9开始),从第二行到最后一行的映射中获取
“LongNumber”
的值后,会插入一个额外的强制转换。这:

versionDocInfo.put(versionDoc.get("LongNumber"),"abc");
汇编如下:

versionDocInfo.put((String) versionDoc.get("LongNumber"),"abc");

使用
javac 1.8.0_162
编译代码时,从第二行到最后一行的字节码是:

 114: aload         7
 116: aload         6
 118: ldc           #6                  // String LongNumber
 120: invokeinterface #16,  2           // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
 125: ldc           #17                 // String abc
 127: invokeinterface #7,  3            // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
请注意,
120:
之后没有
checkcast
指令。但是,当使用
javac9.0.4
时:

 114: aload         7
 116: aload         6
 118: ldc           #6                  // String LongNumber
 120: invokeinterface #16,  2           // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
 125: checkcast     #17                 // class java/lang/String
 128: ldc           #18                 // String abc
 130: invokeinterface #7,  3            // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
请注意,
125:
处有一条
checkcast
指令

此指令起作用,因为它基本上是在从
versionDoc
映射获取值后执行额外的类型检查。基本上是这样做的:

versionDocInfo.put((String) versionDoc.get("LongNumber"),"abc");
在Java11中(从9开始)


如评论中所述;
“LongNumber”
的值类型为
整数
,由于前面几行未选中的强制转换,该值位于
映射
中:

docIdVersionNameMap.addAll((List<Map<String, String>>) versionMap1.get(0));
docIdVersionNameMap.addAll((列表)versionMap1.get(0));
即使其中一个值是
整数,也可以将
映射
间接转换为
映射
。不同之处在于,从映射中获取值后,有一个额外的强制转换来检查类型


请注意,缺少的
checkcast
javac
中的一个错误,因此使用不同的编译器或
javac
的不同版本进行编译可能会导致不同的行为。

我在Java 8中遇到相同的错误,这并不奇怪-您正试图将一个
整数
作为
映射
中的一个键。Java
1.8_60
非常古老,但仍然很难相信它运行正常。使用稍新的版本,我得到了
java版本“1.8.0_112”java(TM)SE运行时环境(build1.8.0_112-b15)。。。线程“main”java.lang.ClassCastException中的异常:…
@YassinHajaj作为键:
versionDocInfo.put(versionDoc.get(“LongNumber”),“abc”)@Eran,你说得对。奇怪的是,同样的代码在
ideone.com[HotSpot 8u112]
JDoodle[JDK 10.0.1]
上运行(只是用正确的导入复制过去)我没有获得接近的选票。请不要关闭它,这段代码可以在多个平台上运行,也可以在我的本地PC上运行。我们如何解释它在jdoodle.com上的Java 10上运行,以及我们中的一些人在Java 8上有代码失败,而另一些没有?@YassinHajaj嗯,这确实是
javac
的错,而不是
Java
,因此,如果您使用Eclipse来编译该类,您可能会得到不同的行为。如果可以,您应该使用
javap-c…
@YassinHajaj检查字节码。我不确定jdoodle.com是否正确,使用相同版本的Java10,我得到了抛出的CCE。一定是关于他们的设置。。。使用例如
var x=10
进行测试,这不会在jdoodle.com上编译,所以我猜他们正在使用JDK 8中的
javac
进行编译,然后使用java 10运行。好的,谢谢,在本地签入字节码,它确实没有调用checkcast操作!谢谢,这很有趣:)
docIdVersionNameMap.addAll((List<Map<String, String>>) versionMap1.get(0));