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{}