I am puzzled by this compilation error. Consider the code snippet below, ConcreteClass1
has the following compilation error:
Error:(16, 28) java: incompatible types: java.util.Map java.lang.String,java.lang.String> cannot be converted to java.util.Map java.lang.String,java.lang.Object>
Yet ConcreteClass2
compiles successfully, simply because it extends AbstractClass
rather than AbstractClass<Object>
. Why is this?
abstract class AbstractClass<T extends Object> {
void testGenerics(Map<String, Object> map) {
}
}
class ConcreteClass1 extends AbstractClass<Object> {
public void testGenerics() {
Map<String, String> map = new HashMap<>();
super.testGenerics(map);
}
}
class ConcreteClass2 extends AbstractClass {
public void testGenerics() {
Map<String, String> map = new HashMap<>();
super.testGenerics(map);
}
}
ConcreteClass2
is declared as a raw type, due to omitted generic inforamtion. As per official Raw Types tutorial:
Raw types show up in legacy code because lots of API classes (such as the Collections classes) were not generic prior to JDK 5.0. When using raw types, you essentially get pre-generics behavior
Because of above testGenerics(Map<String, Object> map)
is interpreted as testGenerics(Map map)
and it can be invoked with any Map
object. All due to backward compatibility with pre Java 5 code.
You can take a look at JLS 4.8 Raw Types.