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) ```

Original source

Related problems