当使用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中遇到相同的错误,这并不奇怪-您正试图将一个整数
作为映射
中的一个键。Java1.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));