views:

61

answers:

2

It's obvious that a parent class's object can hold a reference to a child, but does this not hold true in case of parameterised collection ??

eg:

Car class is parent of Sedan

So

public void doSomething(Car c){
    ...
}

public void caller(){
    Sedan s = new Sedan();
    doSomething(s);
}

is obviously valid

But

public void doSomething(Collection<Car> c){
    ...
}

public void caller(){
    Collection<Sedan> s = new ArrayList<Sedan>();
    doSomething(s);
}

Fails to compile

Can someone please point out why? and also, how to implement such a scenario where a function needs to iterate through a Collection of parent objects, modifying only the fields present in parent class, using parent class methods, but the calling methods (say 3 different methods) pass the collection of three different subtypes..

Ofcourse it compiles fine if I do as below:

public void doSomething(Collection<Car> c){
    ...
}

public void caller(){
    Collection s = new ArrayList<Sedan>();
    doSomething(s);
}
+4  A: 

Use

public void doSomething(Collection<? extends Car> c){}

or (as suggested)

public <T extends Car> void doSomething(Collection<T> c){}

This would mean that the Collection is of any subclass of Car (or Car itself), rather than "It's a collection of Car instances only"

This is because collections are invariant, unlike arrays, which are covariant. To quote Effective Java:

Covariant [..] means that if Sub is a subtype of Super, then the array type Sub[] is a subtype of Super[]. Generics, by contrast, are invariant: for any two distinct types Type1 and Type2, List<Type1> is neigther a subtype nor a supertype of List<Type2>.

Bozho
If you know that the collection is homogeneous, the better way to write the method signature is <code>public <T extends Car> void doSomething(Collection<T> c)</code>
Dilum Ranatunga
+2  A: 

doSomething needs to be declared doSomething(Collection<? extends Car> c). Declared that way, you will not be able to add any elements to the collection, because you do not know what specific subclass of Car that collection is supposed to contain.

The general issue here is that a Collection<Sedan> simply cannot be considered a subclass of Collection<Car> because you can't do everything on a Collection<Sedan> that you can on a Collection<Car>. For instance, you can add a SportsCar to a Collection<Car> because a SportsCar is a Car. You can't add a SportsCar to a Collection<Sedan> because a SportsCar is not a Sedan.

ColinD