The list <a> canot is sent to the method (List <super-class-of-a>) - why not?

I must have missed something regarding generics in Java, but why doesn't this work?

List<String> list = new ArrayList<String>();

      

cannot be sent:

method( List<Object> );

      

But it won't work? Why?

But if this method was:

method( Object o )

      

it can be used with:

method( new String("hello") ) 

      

no problem

q1) String expands Object, why can't it be passed?

List<Object>

      

q2) and why

method( List<? extends Object> ) 

      

work? Who cares?

+2


source to share


6 answers


See 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 cannot be allowed to work as it List<String>

will contain Object

afterwards, discarding all type safety that generators generate.

+10


source


List<String>

is not a subtype List<Object>

as you might expect, for the reasons mentioned in 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 put anything. You can pass, List<String>

or, in theory, a list of any String subtype to this method. You can also define it as



method(List<? super String> list)

      

which will allow you to put strings into a list, but only read objects from it. Then you can pass List<String>

or List<Object>

. Note that it doesn't make much sense in this example (since you can't subclass String), but it makes sense for other types of hierarchy

+7


source


What if the () method was defined as follows?

void method(List<Object> list) {
  list.add(new Long(1));
}

      

Nothing wrong with this right? oops if you didn't go to the list <String>

!

It's hard to explain intuition, but I can point out that the get () methods on the List won't present such a problem, right? Since the list only promises returns an object. These are the "set" or "add" methods. There it must match the supertype, not the subtype. The restrictive view goes both ways, generally in generics. So this is different from just passing parameters where the subclass is always ok.

+5


source


Generics are tricky, you can read this . I have nothing to explain that this will be enough. Anyway, the short answer is: If the List of Strings is an assignable list of objects than when using a list of objects as a reference, you can add something that is not a String thus invalidating the "List" String definition. But it is possible to assign a List of String to the list of unknowns, since the list of unknowns can be read rather than added. Btw, List? is it the same as List of? extends Object

+3


source


The problem you are facing is Covariance denominated .

In principle, if the giraffe is an animal, why not List<Giraffe>

be List<Animal>

? This makes general sense, but can cause problems like Sean mentioned .

The second question is related to how Java solves this problem. Restricted wildcards allow you to define covariant (and contravariant) lists that are safe from the problems mentioned. For example, you cannot add an item to a wildcard list.

+2


source


Is it for the same reason why it doesn't work?

private void hello(List<? extends Object> l) {
    l.add( new String(""));
}

      

0


source







All Articles