Java does not permit Collection<Car>
as a subtype of Collection<Vehicle>
. Is this because Collection<Car>
cannot be used in place of every Collection<Vehicle>
as the Collection<Vehicle>
could contain elements which are other subtypes of Vehicle such as Motorbike, therefore it violates Liskov substitution principle?
-
This is more related to the invariance challenge in using generics and the covariance response that goes with it – alainlompo Apr 22 '15 at 11:08
4 Answers
Generally, Collection
s violate the Liskov substitution principle due to the existence of “optional operations”, i.e. the mutation methods may be unusable for a particular implementation.
Regarding the type safety, however, it works that way:
Assuming that Car
is a subtype of Vehicle
, a Collection<Car>
is a type that allows an operation like
Collection<Car> c=…;
Car car=c.iterator().next();
which Collection<Vehicle>
doesn’t. On the other hand, Collection<Vehicle>
is a type that allows an operation like
Collection<Vehicle> c=…;
Vehicle v=…;
c.add(v);
which Collection<Car>
doesn’t. Therefore, neither of these Collection
types is a subtype of the other.

- 285,553
- 42
- 434
- 765
-
1See http://stackoverflow.com/questions/22050848/do-collections-unmodifiablexxx-methods-violate-lsp for a debate on whether collection mutation methods violate LSP. – jaco0646 Aug 03 '16 at 15:42
Not exactly. The other way around:
That a Collection<Car>
only contains Car
s is fine, even though a Collection<Vehicle>
might contain other types of vehicles. You can still give a Collection<Car>
to anyone who can handle elements from a Collection<Vehicle>
.
But Collection<Car>
cannot be used in place of a Collection<Vehicle>
, because you could put a Bicycle
into a Collection<Vehicle>
(but not in a Collection<Car>
). So you cannot give the Collection<Car>
to someone who wants to collect vehicles.

- 257,207
- 101
- 511
- 656
Collection<T>
is a type constructor, so Collection<Car>
is a type and Collection<Vehicle>
is another type.
Now the question, if a Collection<Car>
can be used where a Collection<Vehicle>
is required, is a matter of variance (co-variance is this case).
Liskov substitution principle exceed type conformity in a way that it not only requires to provide more, require less, but also that the contract of the supertype is kept, see Wikipedia.

- 7,701
- 6
- 52
- 64
Note that a Collection<Car>
is invariant over the component type Car
. So if you want to use a collection of vehicles which could be cars, bikes, trains, etc., you should take a covariant collection Collection<? extends Vehicle>
.
Of course, if you have a CarFactory
with a produce method that should park the produced cars somewhere, a contravariant produce(Collection<? super Car>)
method would be the most useful implementation.

- 13,815
- 8
- 40
- 72