As we've seen the subtyping relation of generic types is invariant. Sometimes, though, we'd like to use generic types in the same way we can use ordinary types:
Narrowing a reference (covariance)
Widening a reference (contravariance)
Let's suppose, for example, that we've got a set of fruit baskets, each one of a different kind of fruit. We'd like to be able to write methods that could accept a any of them. More formally, given a subtype A of a type B, we'd like to find a way to use a reference (or a method parameter) of type C<B> that could accept instances of C<A>.
To accomplish this task we can use a wildcard with extends, such as in the following example:
List<Apple> apples = new ArrayList<Apple>();
List<? extends Fruit> fruits = apples;
? extends reintroduces covariant subtyping for generics types: Apple is a subtype of Fruit and List<Apple> is a subtype of List<? extends Fruit>.
Upper Bounds Example
Let's now introduce another wildcard: ? super. Given a supertype B of a type A, then C<B> is a subtype of C<? super A>:
List<Fruit> fruits = new ArrayList<Fruit>();
List<? super Apple> appFruits= fruits;
->> appFruits can hold reference of either List or List of any type which is super of Apple