Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics super vs. extends

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)
like image 924
Maggie Avatar asked Feb 18 '23 16:02

Maggie


1 Answers

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

like image 169
Heinzi Avatar answered Feb 28 '23 14:02

Heinzi