Imagine having this hierarchy
1. Extends
By writing
List extends C2> list;
you are saying that list will be able to reference an object of type (for example) ArrayList whose generic type is one of the 7 subtypes of C2 (C2 included):
- C2:
new ArrayList();, (an object that can store C2 or subtypes) or
- D1:
new ArrayList();, (an object that can store D1 or subtypes) or
- D2:
new ArrayList();, (an object that can store D2 or subtypes) or...
and so on. Seven different cases:
1) new ArrayList(): can store C2 D1 D2 E1 E2 E3 E4
2) new ArrayList(): can store D1 E1 E2
3) new ArrayList(): can store D2 E3 E4
4) new ArrayList(): can store E1
5) new ArrayList(): can store E2
6) new ArrayList(): can store E3
7) new ArrayList(): can store E4
We have a set of "storable" types for each possible case: 7 (red) sets here graphically represented
As you can see, there is not a safe type that is common to every case:
- you cannot
list.add(new C2(){}); because it could be list = new ArrayList();
- you cannot
list.add(new D1(){}); because it could be list = new ArrayList();
and so on.
2. Super
By writing
List super C2> list;
you are saying that list will be able to reference an object of type (for example) ArrayList whose generic type is one of the 7 supertypes of C2 (C2 included):
- A1:
new ArrayList();, (an object that can store A1 or subtypes) or
- A2:
new ArrayList();, (an object that can store A2 or subtypes) or
- A3:
new ArrayList();, (an object that can store A3 or subtypes) or...
and so on. Seven different cases:
1) new ArrayList(): can store A1 B1 B2 C1 C2 D1 D2 E1 E2 E3 E4
2) new ArrayList(): can store A2 B2 C1 C2 D1 D2 E1 E2 E3 E4
3) new ArrayList(): can store A3 B3 C2 C3 D1 D2 E1 E2 E3 E4
4) new ArrayList(): can store A4 B3 B4 C2 C3 D1 D2 E1 E2 E3 E4
5) new ArrayList(): can store B2 C1 C2 D1 D2 E1 E2 E3 E4
6) new ArrayList(): can store B3 C2 C3 D1 D2 E1 E2 E3 E4
7) new ArrayList(): can store C2 D1 D2 E1 E2 E3 E4
We have a set of "storable" types for each possible case: 7 (red) sets here graphically represented
As you can see, here we have seven safe types that are common to every case: C2, D1, D2, E1, E2, E3, E4.
- you can
list.add(new C2(){}); because, regardless of the kind of List we're referencing, C2 is allowed
- you can
list.add(new D1(){}); because, regardless of the kind of List we're referencing, D1 is allowed
and so on. You probably noticed that these types correspond to the hierarchy starting from type C2.
Notes
Here the complete hierarchy if you wish to make some tests
interface A1{}
interface A2{}
interface A3{}
interface A4{}
interface B1 extends A1{}
interface B2 extends A1,A2{}
interface B3 extends A3,A4{}
interface B4 extends A4{}
interface C1 extends B2{}
interface C2 extends B2,B3{}
interface C3 extends B3{}
interface D1 extends C1,C2{}
interface D2 extends C2{}
interface E1 extends D1{}
interface E2 extends D1{}
interface E3 extends D2{}
interface E4 extends D2{}