3
votes

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);
    }
}
2

2 Answers

3
votes

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.

2
votes

Thats the beauty of type checks. :)

ConcreteClass2 extends a raw AbstractClass and thus there is no compile time type checking. However compiler gives you a warning to not use Raw types for Parameterized classes.

When a raw type is used, the type for constructors, instance methods and non-static fields are also erased.