TL; DR - Контекст - это все!
Неформально, " переменная типа "и « параметр типа » взаимозаменяемо используются как синонимы друг для друга [ даже Гиладом Брачей - создателем реализации Generics в Java ].
Формально, однако, JLS явно описывает их как две разные - , но тесно связанные - абстракции.
В прошлом яУ меня были похожие вопросы о менее чем кристально чистом использовании терминов « параметр типа » и « переменная типа » во многих публикациях по дженерикам.
Из моей интерпретации более поздняя версия Java 8 JLS , TypeParameter
- это то, что появляется в параметризованном классе или параметре типа методаsection [ <>
часть объявления ].
JLS говорит: " Введена переменная типаредактируется объявлением параметра типа ... ".Я понимаю, что это означает, что для использования TypeVariable
необходимо сначала заполнить раздел параметра типа метода [ или класса '], следуя правилам, указанным дляобъявляя TypeParameter
...
TypeParameter:
{TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
Annotation
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
AdditionalBound:
& InterfaceType
Чтение вышеупомянутую синтаксическую продукцию для TypeParameter
и этот для TypeVariable
...
TypeVariable:
{Annotation} Identifier
... Я интерпретирую эти два произведения, чтобы означать, что если идентификатор T
используетсяиспользуется в контексте, где T
имеет [ или может иметь ] a TypeBound
после него, тогда T
а TypeParameter
.В качестве альтернативы, если идентификатор T
используется в контексте, где TypeBound
s не разрешены, тогда T
является TypeVariable
.
Я думаю, что TypeParameter
аналогичен формальному параметру объявление метода.
Когда JLS говорит: " Переменная типа - это неквалифицированный идентификатор, используемый как тип в теле класса, интерфейса, метода и конструктора " , я понимаю, что это означает, что объявление TypeParameter
в разделе параметров типа также аналогично объявлению класса, который впоследствии может быть использован в качестве ссылочного типа, скажем, экземплярапеременная - в некотором смысле .
Под этим я подразумеваю, чтобы следующее было допустимым ...
class Foo {
private Bar bar;
}
class Boff extends Foo { }
.. тогда вы должны сначала ввести объявление типа Bar
, прежде чем его можно будет использовать в теле Foo
.Аналогично, параметр типа <T extends Foo>
должен быть сначала объявлен для того, чтобы следующее было допустимым ...
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;
}
}
И если мне позволено быть четнымболее конкретно ...
Baz<Boff> buzz = new Baz<>();
... Boff
внутри <>
алмаза не является типом переменная или тип параметр .Это тип аргумент .