Вывод типа: параметры типа Java 7

сегодня мы говорили о преимуществах Java 7 в нашей компании. Начиная с Java 7 есть возможность определить следующую строку

Map<String, List<String>> myMap = new HashMap<String, List<String>>();

as

Map<String, List<String>> myMap = new HashMap<>();

Мы долго обсуждали описанную выше тему. У некоторых из нас было мнение, что это вывод типа (как ключевое слово var в C#) и тип будет вычисляться во время выполнения, другие думали, что это просто более простой способ объявить какую-то переменную и никакого вывода нет, потому что тип известен по контексту во время компиляции.

Пожалуйста, дайте разъяснения. Как работает техника?

РЕДАКТИРОВАТЬ: Официальная документация Oracle не содержит точной документации по этому поводу. http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html


person agassner    schedule 05.08.2014    source источник
comment
Это вывод типа. Для получения полной информации о том, как это работает, вам необходимо прочитать спецификацию языка Java.   -  person davmac    schedule 05.08.2014
comment
Соответствующая официальная документация Oracle находится здесь: docs.oracle.com/javase/specs - и более конкретно здесь: docs.oracle.com/javase/tutorial/java/ generics/types.html и docs.oracle.com/javase/specs/jls/se7/html/ (во всяком случае, для Java 7).   -  person davmac    schedule 05.08.2014
comment
И вывод типа всегда происходит во время компиляции, а не во время выполнения. См. en.wikipedia.org/wiki/Type_inference.   -  person davmac    schedule 05.08.2014


Ответы (3)


На самом деле это вывод типа.

Алмазный оператор (<>) позволяет определить правую часть присваивания как настоящий общий экземпляр с теми же параметрами типа, что и левая часть, без необходимости вводить эти параметры повторно (поскольку компилятор выводит тип(ы) с левой стороны).

Из Часто задаваемые вопросы Анжелики Лангер по дженерикам:

Он (оператор ромба) обозначает пустые угловые скобки, которые используются для выведения типа в новом -выражении.

Больше информации:

person Konstantin Yovkov    schedule 05.08.2014
comment
Абсолютно. Помните, что параметризованные типы (они же Generics) стираются во время компиляции. Отсюда следует, что они не проверяются во время выполнения. Компилятор проверяет их, но во время компиляции (после чего они стираются). - person Edwin Buck; 05.08.2014
comment
@EdwinBuck прав, но какое значение имеет этот вопрос? Даже если бы стирания типа не произошло, ответ не изменился бы. Вывод типа все равно будет происходить. - person davmac; 05.08.2014
comment
Стирание типа всегда происходит в Generics. Вот почему вы не можете делать для них какой-либо вывод типа во время выполнения, поэтому это утверждение имеет какое-то отношение к тому, происходит ли вывод алмаза во время выполнения (что является частью того, что предполагает один человек в вопросе) - person Edwin Buck; 05.08.2014

«У некоторых из нас было мнение, что это вывод типа (как ключевое слово var в C#) и тип будет вычисляться во время выполнения, другие думали, что это всего лишь более простой способ объявить какую-то переменную и нет никакого вывода, потому что тип известны из контекста во время компиляции».

Ref: Универсальный класс определяется в следующем формате:

class name<T1, T2, ..., Tn> { /* ... */ }

Раздел параметра типа, разделенный угловыми скобками (‹>), следует за именем класса. Он определяет параметры типа (также называемые переменными типа) T1, T2, ... и Tn.

Во время компиляции параметр type удаляется и преобразуется в Необработанный тип в процессе стирание типа означает, что указанное выше объявление будет преобразовано в:

class name { /* ... */ }

Что касается синтаксиса объявления некоторого класса с дженериком, например:

-- (Case I)
Map<String, List<String>> myMap = new HashMap<String, List<String>>(); 

OR

-- (Case II)
Map<String, List<String>> myMap = new HashMap<>();

В case I правостороннее объявление является избыточным, что может быть выведено из левостороннего объявления объекта, поэтому запись в правой части считалась ненужной, поскольку Java7

person Vishrant    schedule 05.08.2014

Во-первых, обратите внимание, что нет абсолютно никакой разницы в скомпилированном байт-коде между new HashMap<String, List<String>>() и new HashMap<Integer, String>() и new HashMap(), потому что они одинаковы после стирания типа. Поэтому все, что вы заключаете в скобки (если есть) при создании объекта, используется только во время компиляции.

Некоторые люди говорят, что с оператором алмаза компилятор «выводит» тип, который туда входит. Но давайте подумаем, зачем компилятору вообще это нужно "выводить". Зачем компилятору знать, что там происходит?

Если вы вызываете конструктор, который принимает некоторые параметры типа K или V, то тип, заключенный в скобки, имеет значение, поскольку он действует как ограничение на тип объекта, который вы можете передать в качестве аргумента. В этом случае компилятор должен сделать вывод.

Однако в случае вопроса, когда вы вызываете конструктор без параметров, компилятору действительно не нужно знать, что находится в скобках - не имеет значения, знает ли компилятор или нет, потому что 1) он знает не нужен для генерации байт-кода, и 2) мы знаем, что существует какой-то тип, который будет работать (нет типа параметра, который может привести к сбою компиляции). Таким образом, в этом случае компилятор может не «выводить», если он этого не хочет.

person newacct    schedule 06.08.2014