If a reference of an Apple instance can be assigned to a reference of a Fruit, as seen above, then what's the relation between, let's say, a List<Apple> and a List<Fruit>? Which one is a subtype of which? More generally, if a type A is a subtype of a type B, how does C<A> and C<B> relate themselves?
Surprisingly, the answer is: in no way. In more formal words, the subtyping relation between generic types is invariant.
Eg.
List<Apple> apples = new ArrayList<>();
List<Apple> foulApples = apples; //fine
Collection<Apple> greenApples = apples; //fine again However this is not fine:
List<Apple> apples = new ArrayList<>();
List<Fruit> fruits = apples;//Error
and so does the following:
List<Apple> apples;
List<Fruit> fruits = ...;
apples = fruits;
But why? Is an apple is a fruit, a box of apples (a list) is also a box of fruits.
In some sense, it is, but types (classes) encapsulate state and operations. What would happen if a box of apples was a box of fruits?
List<Apple> apples = ...;
List<Fruit> fruits = apples;
fruits.add(new Strawberry());
If it was, we could add other different subtypes of Fruit into the list and this must be forbidden.
So what if they were covariant?
Please go through the comments to see what is the problem:
List<Integer> li = new ArrayList<Integer>(); li.add(new Integer(122)); List<Object> lo = li; // Problem starts here Object num = lo.get(0); // Nothing wrong with this lo.add("Bang!"); // This would be OK through // lo but what about li
Integer i = li.get(1); // ClassCastException
No comments:
Post a Comment