Generics super vs. extends
generic-type-argument, generics, java, scjp
Solution
Your first declaration
Organic<? extends Organic> compound
means that `compound` could be an `Organic<SomeSubtypeOfHexane>` (since `Aliphatic` extends `Organic`, `Hexane` extends `Aliphatic` and `SomeSubtypeOfHexane` extends `Hexane`).
In that case, `compound.react(new Organic())`, `compound.react(new Aliphatic())` and `compound.react(new Hexane())` would lead to a type error, since `E` in `compound` must be a `SomeSubtypeOfHexane` (or subtype thereof).
Your second declaration
Organic<? super Aliphatic> compound
means that `compount` could be an `Organic<Aliphatic>`.
In that case `compound.react(new Organic())` would lead to a type error, since `E` must be an `Aliphatic` (or subtype thereof).
Remember that declaring a variable using `A<? extends B>` or `A<? super B>`
- extends the amount of objects that can be assigned to it, and, in consequence,
- restricts what can be done with the variable.
Since the exact type of the class is unknown (only a constraint is known), the compiler has to err on the side of safety and disallow certain operations that are either not co- or contravariant. (If you are not already familiar with it, Co- and contravariance is the scientific background of these types of generics.)
Problem
Just when I thought I finally understood generics, I came across the following example: ``` public class Organic<E> { void react(E e) { } static void main(String[] args) { //1: Organic<? extends Organic> compound = new Aliphatic<Organic>(); //2: Organic<? super Aliphatic> compound = new Aliphatic<Organic>(); compound.react(new Organic()); compound.react(new Aliphatic()); compound.react(new Hexane()); } } class Aliphatic<F> extends Organic<F> { } class Hexane<G> extends Aliphatic<G> { } ``` It says, if line 1 is uncommented, the following will not compile: ``` compound.react(new Organic()); compound.react(new Aliphatic()); compound.react(new Hexane()); ``` while if line 2 is ucommented, the following will not compile: ``` compound.react(new Organic()); ``` In the second example, Aliphatic and it's supertypes are allowed. So why isn't Aliphatic allowed? In the first example, why isn't `new Organic` allowed?? 1st compiler error: ``` - The method react(capture#1-of ? extends Organic) in the type Organic<capture#1-of ? extends Organic> is not applicable for the arguments (Organic) - The method react(capture#2-of ? extends Organic) in the type Organic<capture#2-of ? extends Organic> is not applicable for the arguments (Aliphatic) - The method react(capture#3-of ? extends Organic) in the type Organic<capture#3-of ? extends Organic> is not applicable for the arguments (Hexane) ``` 2nd compiler error: ``` - The method react(capture#1-of ? super Aliphatic) in the type Organic<capture#1-of ? super Aliphatic> is not applicable for the arguments (Organic) ```