Определение типа переменной и параметра - PullRequest
4 голосов
/ 16 августа 2011

Я читаю дженерики в Java, используя Спецификацию языка Java, третье издание . В разделе « 4.6 Erasure » определено тип стирания. На стирании переменной типа написано

Стирание переменной типа (§4.4) - это стирание ее самой левой границы.

Это немного смущает меня относительно различия между переменной типа и параметром типа , поскольку в разделе " 4.4 Типовые переменные " есть определение: TypeParameter: TypeVariable TypeBound где граница не является обязательной. Но, возможно, вы можете идентифицировать переменную типа с параметром типа, в котором она появляется, поскольку переменная типа может только (?) Появляться в одном «контексте», а затем крайняя левая граница переменной типа определяется как крайняя левая граница соответствующего параметра параметра или Object если в параметре типа нет явной границы?

Ответы [ 2 ]

6 голосов
/ 16 августа 2011

Если для переменной типа не задана граница, предполагается объект.

Нашел по вашей ссылке. Это означает, что с учетом FirstClass<T extends String> и SecondClass<V> вы получите:

  1. Класс: FirstClass Тип Параметр: T extends String. Переменная типа: T. Тип привязки: String.
  2. Класс: SecondClass Тип Параметр: V Тип Переменная: V. Тип Bound: по умолчанию Object.

Редактировать: По Тип параметра , Тип переменной и Тип привязки Я имею в виду не правило грамматики, а понятие. Поэтому extends - это просто ключевое слово.

О самой левой границе вы можете найти ответ по той же ссылке, два предложения после первой цитаты:

Порядок типов в границе важен только в том смысле, что стирание переменной типа определяется первым типом в ее границе и что тип класса или переменная типа может появляться только в первой позиции.

1 голос
/ 02 мая 2017

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 внутри <> алмаза не является типом переменная или тип параметр .Это тип аргумент .

...