Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic return types - why can't I do this?

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;
    }
}
like image 722
csvan Avatar asked Mar 05 '26 21:03

csvan


1 Answers

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();
like image 106
John Kugelman Avatar answered Mar 08 '26 11:03

John Kugelman