Reputation: 12285
I must have missed something regarding generics in Java, but why does this not work?
List<String> list = new ArrayList<String>();
cannot be sent to:
method( List<Object> );
But it does not work? How come?
But if the method was:
method( Object o )
it can be used with:
method( new String("hello") )
without any problems
q1) String does extend Object, why cannot it be passed to?
List<Object>
q2) and why does
method( List<? extends Object> )
work? What's the difference?
Upvotes: 2
Views: 324
Reputation: 12285
Is that the same reason why this does not work?
private void hello(List<? extends Object> l) {
l.add( new String(""));
}
Upvotes: 0
Reputation: 83846
Watch this:
List<String> stringList = new ArrayList<String>();
List<Object> objectList = stringList; // if this was allowed…
objectList.add(new Object());
String s = stringList.get(0); // …this would throw a ClassCastException
Obviously, this can not be allowed to work as the List<String>
would contain an Object
afterwards, throwing away all the type-safety that generics are aimed to give you.
Upvotes: 10
Reputation:
List<String>
is not a subtype of List<Object>
, as you might expect, for reasons mentioned in the other answers.
However, you can define your method like this:
method(List<? extends String> list)
which will allow you to get Strings from the list, but not to put anything in. You could pass a List<String>
or, theoretically, a List of any subtype of String into the method.
You can also define it as
method(List<? super String> list)
which will allow you to put Strings in the list, but only read Objects from it. You can then pass in a List<String>
or a List<Object>
.
Note that it doesn't make much sense in this example (since you can't subclass String), but it does make sense for other type hierarchies
Upvotes: 7
Reputation: 48265
The problem you are facing here is denominated Covariance.
Basically, if a Giraffe is an Animal why shouldn't a List<Giraffe>
be a List<Animal>
? This makes total sense but it can cause problems like Sean mentioned.
Your second question as to do with the way Java addresses this problem. Bounded Wildcards allow you to define covariant(and contravariant) Lists that are safe from the problems mentioned. For instance, you can not add an element to a Bounded Wildcard List.
Upvotes: 2
Reputation: 66876
What if method() were defined like this?
void method(List<Object> list) {
list.add(new Long(1));
}
Nothing wrong with that right? oops, unless you passed in a List<String>
!
It's kind of hard to explain the intuition, but I can point out that the get() methods on a List would present no such problem, right? Since list only promises to return an Object. It's the "set" or "add" methods that are the issue. There it needs to match on supertype, not subtype. The restriction kind of goes both ways, in general, in generics-land. So it's different than simple parameter passing, where a subclass is always OK.
Upvotes: 5
Reputation: 6231
Generics is complex, you may want to read this. I don't thing anything I explain here will be sufficient. Anyway, the short answer is: If List of String is assignable to List of Object, than using the List of Object as a reference, one can add something that is not String to it thus invalidating the "List of String" definition. But it is possible to assign List of String to List of unknown, as a list of unknown can only be read, not added into. Btw, List of ? is the same thing as List of ? extends Object
Upvotes: 3