TL;DR — Context is everything!
Informally, "type variable" and "type parameter" are used interchangeably as synonyms for each other [even by Gilad Bracha — the creator of Java's Generics implementation].
Formally, however, the JLS explicitly describes them as two different — but closely-related — abstractions.
In the past, I have had similar questions myself about the less-than-crystal-clear usage of the terms "type parameter" and "type variable" in a lot of the literature on generics.
From my interpretation of the more-recent Java 8 JLS, a TypeParameter
is what appears in a parameterized class' or method's type parameter section [the <>
part of a declaration].
The JLS says, "A type variable is introduced by the declaration of a type parameter...". I interpret that to mean that, in order to use a TypeVariable
, you must first fill out the method's [or the class'] type parameter section by following the rules specified for declaring a TypeParameter
...
TypeParameter:
{TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
Annotation
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
AdditionalBound:
& InterfaceType
Reading the above syntactic production for TypeParameter
and this one for TypeVariable
...
TypeVariable:
{Annotation} Identifier
...I interpret those two productions to mean that if an identifier T
is being used in a context where T
has [or can have] a TypeBound
after it, then T
is a TypeParameter
. Alternatively, if an identifier T
is being used in a context where TypeBound
s are not allowed, then T
is a TypeVariable
.
I think of a TypeParameter
as being analogous to a formal parameter of a method declaration.
When the JLS says, "A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies", I interpret that to mean that declaring a TypeParameter
in the type parameter section, is also sort of analogous to declaring a class that can be subsequently used as a reference type of, say, an instance variable — in a sense.
By that I mean, in order for the following to be legal...
class Foo {
private Bar bar;
}
class Boff extends Foo { }
..then you must first introduce the declaration of the Bar
type before it can be used in the body of Foo
. Analogously, the type parameter <T extends Foo>
must first be declared in order for the following to be legal...
class Baz<T extends Foo> { /* The TypeParameter that "introduces" T comes first */
private T quux; /* now T is a TypeVariable in this context */
/* <U extends Number> is the TypeParameter that "introduces" the TypeVariable, U */
public <U extends Number> List<? super U> m( Class<U> clazz ) throws Exception { /* <U extends Number> is the TypeParameter */
U u = clazz.newInstance( ); /* U is a TypeVariable in this context */
/*...*/
List<? super U> list = new LinkedList<>(); /* U is a TypeVariable in this context; just like it is in this method's return type */
/*...*/
list.add( u );
/*...*/
return list;
}
}
And if I'm allowed to be even more specific...
Baz<Boff> buzz = new Baz<>();
...the Boff
inside the <>
diamond, is neither a type variable nor a type parameter. It is a type argument .