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;
}
}
Map<String, String> map = instance2.getMap(); // 1
The compiler sees a call to X.getMap() which has a return type of Map<String, ? extends Object>. This is not convertible to Map<String, String>. It doesn't matter that instance2 is of type Y at runtime; this is pure compile-time static type checking that's failing.
List<String> list = instance.getList(); // 2
The same reasoning applies. The compile-time type of instance is A, and A.getList() returns a List<? extends Object> which is incompatible with List<String>.
Mind you, it's not an issue specific to generics. This would also fail to compile for the same reason:
class A { Object getObject(); }
class B extends A { String getObject(); }
A a = new B();
String s = a.getObject();
If you want it to work then you need to give the compiler some extra help. Either by casting to the sub-class:
String s = ((B) a).getObject();
Or by casting the return value:
String s = (String) a.getObject();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With