Roedy Green said:
Let me see if I follow:
Collection<? extends Automobile> a = new ArrayList<Automobile>( 10 );
a.add( new Automobile() );
Not allowed. The signature of "add" on Collection<T> is "void add(T)".
The type of "a" doesn't say what type parameter was used to create the
instance that it refers to, only that the parameter was some subclass
of Automobile.
The instance might be an ArrayList<Car>. In that case, the signature
of the actual add method would be "void add(Car)" and it would be
an error to pass an Automobile to it.
a.add( new Car() ); // blocked
Also blocked, for the same reason, since the type parameter of the
actual instance might not be Car or a superclass of Car.
Generally, if something is only known to have type
SomeClass<? extends Foo>
then you can't call methods that expects values of the type
parameter's type, because you don't know what type that is.
Opposite, if something is only known to have a type
SomeClass<? super Foo>
then you can't (as usefully) call methods that return something
of the type paremeter's type (however, you do know that it's
at least an Object
.
So strangely Collection<? extends Automobile> means the exact
opposite.
it means Collection<only Automobile no Cars or Trucks>
No, Liskov's Substitution Principle still holds. You can use an
instance of Car anywhere you expect an Automobile, because a Car *is*
an Automobile. If you have a Collection that you can add Automobiles
to, you can also add Cars. A type of such a collection would be
Collection<? super Automobile>
or just
Collection<Automobile>
What doesn't hold is that Collection<Car> is a Collection<Automobile>.
Neither is a subtype of the other. Instead you have a subtype diagram
that looks like this:
Collection<? extends Automobile>
/ \
Collection<Automobile> Collection<? extends Car>
/
Collection<Car>
(and:
Collection<? super Car>
/ \
Collection<? super Automobile> Collection<Car>
\
Collection<Automobile>
which doesn't draw very well on the same diagram
/L