Consider the snippet below. I understand how overriding works with regard to generic types, and why the return type List<String> (for example) is permitted to override List<? extends Object>. However, I am not entirely clear why a statements such as 1 and 2 fail to compile…should not inheritance apply here as well?
public class Generics {
public static void main(String[] args) {
A instance = new B();
X instance2 = new Y();
Map<String, String> map = instance2.getMap(); // 1
List<String> list = instance.getList(); // 2
}
}
class A {
List<? extends Object> getList() {
return null;
}
}
class B
extends A {
List<String> getList() {
return new LinkedList<String>();
}
}
class X {
Map<String, ? extends Object> getMap() {
return null;
}
}
class Y
extends X {
@Override
Map<String, String> getMap() {
return null;
}
}
The compiler sees a call to
X.getMap()which has a return type ofMap<String, ? extends Object>. This is not convertible toMap<String, String>. It doesn’t matter thatinstance2is of typeYat runtime; this is pure compile-time static type checking that’s failing.The same reasoning applies. The compile-time type of
instanceisA, andA.getList()returns aList<? extends Object>which is incompatible withList<String>.Mind you, it’s not an issue specific to generics. This would also fail to compile for the same reason:
If you want it to work then you need to give the compiler some extra help. Either by casting to the sub-class:
Or by casting the return value: