corgrath
corgrath

Reputation: 12285

List<A> canot be sent to method( List<super-class-of-A> ) - why not?

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

Answers (6)

corgrath
corgrath

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

Bombe
Bombe

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

user8681
user8681

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

bruno conde
bruno conde

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

Sean Owen
Sean Owen

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

RichN
RichN

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

Related Questions