Java 11中的ClassCastException在使用hashmap时不在Java 8中



请查看我的代码:

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&amp; 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)

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

抛出的ClassCastException是正确的。没有投掷它是由javac中的一个错误引起的,该错误是由JDK-8058199在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;

请注意,120:之后没有checkcast指令。但是,使用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;

请注意,125:checkcast指令。

此指令与众不同,因为它基本上是从versionDoc地图获得值后进行额外的类型检查。基本上这样做:

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

在Java 11中(从9开始)。


如评论中所述;"LongNumber"值的类型是Integer,由于未检查的铸件较早,它在Map<String, String>内部:

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

即使其中一个是Integer,您将Map<String, Object>间接施放到Map<String, String>的位置。区别仅在于,从地图获取值后,有一个额外的演员来检查类型。

请注意,丢失的checkcastjavac中的错误,因此使用不同的编译器或不同版本的javac进行编译可能会导致不同的行为。

相关内容

  • 没有找到相关文章

最新更新