I know I'm years late, but this is a top Google result and these answers are all really confusing even though this question as posed has a really clear answer.
Consider the following two Java classes:
abstract class IntT {
int op1();
boolean op2(int something);
}
abstract class StrT {
String op1();
boolean op2(String something);
}
Both IntT
and StrT
are subtypes of the existential type T
you described, you can see that right?
Also, IntT
satisfies the interface T<int>
, and StrT
satisfies the interface T<String>
, you can see that right?
Those are two very different situations, because T
is necessarily the same type as itself, whereas T<int>
and T<String>
are different types. That sounds like a stupidly obvious, but consider this: a List<T>
can contain a mixture of IntT
s and StrT
s as elements, whereas a List<T<int>>
can only contain IntT
s, and a List<T<String>>
can only contain StrT
s:
// preliminaries
IntT someIntT = ...
StrT someStrT = ...
// totally valid:
List<T> mixedList = new ArrayList<T>();
mixedList.add(someIntT);
mixedList.add(someStrT);
// whereas:
List<T<int>> intList = new ArrayList<T<int>>();
intList.add(someIntT); // cool
intList.add(someStrT); // not cool!! Invalid!
List<T<String>> strList = new ArrayList<T<String>>();
strList.add(someStrT); // cool
strList.add(someIntT); // not cool!! Invalid!
(A List<T<Object>>
wouldn't be able to contain a mixture of IntT
s and StrT
s either, because the way the T<X>
interface is defined is invariant in X
, so T<int>
and T<String>
are neither subtypes nor a supertypes of T<Object>
and vice versa. They're just disjoint, unrelated types, like int
and String
are from each other.)