In this simplified example I have a generic class, and a method that returns a Map regardless of the type parameter. Why does the compiler wipe out the types on the map when I don’t specify a type on the containing class?
import java.util.Map; public class MyClass<T> { public Map<String, String> getMap() { return null; } public void test() { MyClass<Object> success = new MyClass<Object>(); String s = success.getMap().get(''); MyClass unchecked = new MyClass(); Map<String, String> map = unchecked.getMap(); // Unchecked warning, why? String s2 = map.get(''); MyClass fail = new MyClass(); String s3 = fail.getMap().get(''); // Compiler error, why? } }
I get this compiler error.
MyClass.java:20: incompatible types found : java.lang.Object required: java.lang.String String s3 = fail.getMap().get(''); // Compiler error
Got it. This actually isn’t a bug, strange as it might seem.
From section 4.8 (raw types) of the JLS:
So even though the method’s type signature doesn’t use any type parameters of the class itself, type erasure kicks in and the signature becomes effectively
In other words, I think you can imagine a raw type as being the same API as the generic type but with all
<X>bits removed from everywhere (in the API, not the implementation).EDIT: This code:
compiles because there’s an implicit but unchecked conversion from the raw
Maptype toMap<String, String>. You can get the same effect by making an explicit conversion (which does nothing at execution time) in the last case: