lucasvw lucasvw - 4 months ago 16
Java Question

Generics and Abstract Methods

I've come across something I find odd in Java and haven't been able to find much information on it. Consider the following code:

public class TestClass {

private static abstract class AbstractClass {
abstract List<? extends Object> getList();
abstract Map<Long, List<? extends Object>> getMap();
}

private static final class ConcreteClass extends AbstractClass {
@Override
List<String> getList() {
return null;
}

@Override
Map<Long, List<String>> getMap() {
return null;
}
}
}


The compiler shows an error on the
getMap()
method:

getMap() in ConcreteClass cannot override getMap() in AbstractClass
return type Map<Long, List<String>> is not compatible with Map<Long, List<? extends Object>>


But the same error is not present for the
getList()
method, yet I would expect either both to work or both to fail. In both cases, the overriding method is delcaring
List<String>
in place of
List<? extends Object>
. Can someone explain this?

Answer

It's because there exists an implicit conversion from List<String> to List<? extends Object>, but not from Map<Long, List<String>> to Map<Long, List<? extends Object>>.

All generic types are invariant unless you're using wildcard types. Since there is no wildcard in the outer Map type, it can't capture any generic type that doesn't match exactly.

If your map type were Map<Long, ? extends List<? extends Object>> then it would work like you expect.

And the other part if the answer is that subclasses can override or implement a supertype method with a different return type, but only if the return type of the subtype's method is implicitly convertible to the supertype method's return type. (In Java 1.4 and below even that wouldn't work: it would be a compile time error if the types didn't match exactly.)

Comments