Assigning a List<Object>
to a List<? super String>
works fine.
Assigning a List<List<Object>>
to a List<List<? super String>>
doesn't compile.
Code
public class Main {
public static void main(String[] args) {
// works fine
List<Object> listOfObject = new ArrayList<>();
takeListSuperString(listOfObject);
// doesn't compile
List<List<String>> listOfListOfObject = new ArrayList<>();
takeListOfListSuperString(listOfListOfObject);
}
static void takeListSuperString(List<? super String> listSuperString) {
}
static void takeListOfListSuperString(List<List<? super String>> listOfListSuperString) {
}
}
Question
Why doesn't List<List<? super String>>
work the same as List<? super String>
?
Also, any idea where I could look up things like this?
A related question is Generics hell: hamcrest matcher as a method parameter. But I don't find the answers there helpful.
Edit
I had to think through JB Nizet's answer for a couple of hours before I finally got it. So I'll expand it a little bit here. Maybe that'll help someone else.
Assuming that assigning a List<List<CharSequence>>
to a List<List<? super String>>
is possible, the following code would compile:
// can only contain instances of CharSequence
List<List<CharSequence>> listOfListOfCharSequences = new ArrayList<>();
List<List<? super String>> listOfListSuperString = listOfListOfCharSequences;
// add a list of objects containing an Integer
List<Object> listOfObjects = new ArrayList<>();
listOfObjects.add(123);
listOfListSuperString.add(listOfObjects);
// Ups.. exception at runtime we are getting an Integer where we expect a CharSequence
CharSequence charSequence = listOfListOfCharSequences.get(0).get(0);
So to prevent ugly exceptions at runtime it is not allowed.
As halex points out this is Generics covariance, same as a List<String>
not being assignable to List<Object>
. And with using List<? extends List<? super String>>
the code would actually compile, because ? extends String
prevents the List.add()
call.