import java.util.List;
import java.util.ArrayList;
interface Canine {}
class Dog implements Canine {}
public class Collie extends Dog {
public static void main(String[] args){
List<Dog> d = new ArrayList<Dog>();
List<Collie> c = new ArrayList<Collie>();
d.add(new Collie());
c.add(new Collie());
do1(d); do1(c);
do2(d); do2(c);
}
static void do1(List<? extends Dog> d2){
d2.add(new Collie());
System.out.print(d2.size());
}
static void do2(List<? super Collie> c2){
c2.add(new Collie());
System.out.print(c2.size());
}
}
The answer for this question tell that when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both. (Kathy and Bert)
What does it mean 'when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both' ?
As far as I know,
The method do1 has List<? extends Dog> d2
so d2 only can be accessed but not modified.
The method d2 has List<? super Collie> c2
so c2 can be accessed and modified and there is no compilation error.
You simply cannot add a
Collie
to aList<? extends Dog>
because this reference may hold for example aList<Spaniel>
.You cannot add a
Cat
to aList<? extends Animal>
because you don't know what kind of list that is. That could be aList<Dog>
also. So you don't want to throw yourCat
into aBlack Hole
. That is whymodification
ofList
declared that way is not allowed.Similarly when you fetch something out of a
List<? super Animal>
, you don't know what you will get out of it. You can even get anObject
, or anAnimal
. But, you can add anAnimal
safely in thisList
.That's a fair first approximation, but not quite correct. More correct would be:
You can only add null to a
Collection<? extends Dog>
because its add method takes an argument of? extends Dog
. Whenever you invoke a method, you must pass parameters that are of a subtype of the declared parameter type; but for the parameter type? extends Dog
, the compiler can only be sure that the argument is of compatible type if the expression isnull
. However, you can of course modify the collection by callingclear()
orremove(Object)
.On the other hand, if you read from a
Collection<? super Dog>
, its iterator has return type? super Dog
. That is, it will return objects that are a subtype of some unknown supertype ofDog
. But differently, the Collection could be aCollection<Object>
containing only instances ofString
. Thereforeso the only thing we know is that instances of Object are returned, i.e. the only type-correct way of iterating such a Collection is
but it is possible to read from a collection, you just don't know what types of objects you will get.
We can easily generalize that observation to: Given
and
we can only pass null to method parameters with declared type
T
, but we can invoke methods with return typeT
, and assign the result a variable of typeSomething
.On the other hand, for
we can pass any expression of type
Something
to method parameters with declared typeT
, and we can invoke methods with return typeT
, but only assign the result to a variable of typeObject
.To summarize, the restrictions on the use of wildcard types only depend on the form of the method declarations, not on what the methods do.
I pasted your code into my IDE. The following error was signalled inside
do1
:This is, of course, as expected.
I pasted your code into IDEONE http://ideone.com/msMcQ. It did not compile for me - which is what I expected. Are you sure you did not have any compilation errors?