The ClassCastException
being thrown is correct. Not having it thrown was caused by a bug in javac
, which was fixed in JDK 9 by JDK-8058199. Your code is technically relying on heap pollution not being picked up, so it was never guaranteed to not break.
Basically, in Java 11 (but starting from 9), an extra cast is inserted after getting the value for "LongNumber"
from the map on the second to last line. This:
versionDocInfo.put(versionDoc.get("LongNumber"),"abc");
Is compiled as:
versionDocInfo.put((String) versionDoc.get("LongNumber"),"abc");
When compiling your code with javac 1.8.0_162
, the bytecode for the second to last line is:
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;
Notice that there is no checkcast
instruction after 120:
. However, when using 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;
Notice that there is a checkcast
instruction at 125:
.
This instruction makes the difference, as it basically does an extra type check after getting the value from the versionDoc
map. Basically doing this:
versionDocInfo.put((String) versionDoc.get("LongNumber"),"abc");
In Java 11 (starting from 9).
As noted in the comments; the type of the value for "LongNumber"
is Integer
, which is inside a Map<String, String>
due to the unchecked cast a few lines earlier:
docIdVersionNameMap.addAll((List<Map<String, String>>) versionMap1.get(0));
Where you indirectly cast a Map<String, Object>
to a Map<String, String>
, even though one of the values is an Integer
. The difference is only that there's an extra cast to check the type after getting the value from the map.
Note that the missing checkcast
was a bug in javac
, so compiling with a different compiler, or different versions of javac
could result in different behavior.
Integer
as a key in aMap<String,String>
. – Greenquist1.8_60
is pretty old but still hard to believe it is running correctly. With a bit newer version I gotjava version "1.8.0_112" Java(TM) SE Runtime Environment (build 1.8.0_112-b15) ... Exception in thread "main" java.lang.ClassCastException: ...
– FitlyversionDocInfo.put(versionDoc.get("LongNumber"),"abc");
– Greenquistideone.com [HotSpot 8u112]
andJDoodle [JDK 10.0.1]
. ideone.com/296BMB & jdoodle.com/online-java-compiler (just copy past it with correct imports) – Garnett