java - 使用HashMap时Java 11中的ClassCastException而不是Java 8中的ClassCastException?
问题描述
请看一下我的代码:
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_1.8_60 (Compile & Run) 中,此代码运行良好,但在 Java 11 中编译和运行时,它会引发以下异常:
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of l
oader 'bootstrap')
at teststringandlong.Trial.main(Trial.java:35)
Java 11 中是否有关于 HashMap 的任何更改?
解决方案
ClassCastException
被抛出是正确的。没有抛出它是由JDK-8058199javac
在 JDK 9 中修复的一个错误引起的。您的代码在技术上依赖于没有被拾取的堆污染,因此永远不能保证它不会中断。
基本上,在 Java 11(但从 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;
请注意, 之后没有checkcast
说明120:
。但是,使用时javac 9.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;
请注意,在 处有checkcast
说明125:
。
versionDoc
这条指令有所不同,因为它基本上在从映射中获取值后会进行额外的类型检查。基本上这样做:
versionDocInfo.put((String) versionDoc.get("LongNumber"),"abc");
在 Java 11 中(从 9 开始)。
如评论中所述;的值的类型"LongNumber"
是,由于前面几行未经检查的强制转换Integer
,它在 a 内:Map<String, String>
docIdVersionNameMap.addAll((List<Map<String, String>>) versionMap1.get(0));
即使其中一个值是Map<String, Object>
a ,您也间接地将 a 强制转换为 a 。不同之处仅在于在从映射中获取值后检查类型的额外转换。Map<String, String>
Integer
请注意,缺少的checkcast
是 中的错误javac
,因此使用不同的编译器或不同版本的编译器javac
可能会导致不同的行为。
推荐阅读
- c# - 混淆.net项目
- flutter - 为什么在调试颤振代码时显示错误
- python - 将实时数据发送到 Django 前端
- css - CSS:将图像无间隙地缩放到 50%
- hex - 为什么十六进制数字以#而不是0x为前缀?
- asp.net-mvc - Web API Url.Link 始终返回 null
- python - 从两个相似的 Pandas DataFrame 中提取范围,并显示与跨标头合并?
- python - 预计审计脚本中的样本为 1% 或 3
- python-3.x - 如何删除文件名中的特殊字符(\u202a 文件名 \u202c\u200f .*mp3)
- javascript - 范围 JavaScript