Почему оператор алмаза используется для вывода типа в Java 7?
List<String> list = new ArrayList();
приведет к предупреждению компилятора.
Однако следующий пример компилируется без предупреждения: List<String> list = new ArrayList<>();
Мне любопытно, почему вообще требуется внедрение алмазного оператора. Почему бы просто не вводить тип в конструкторе, если аргумент типа отсутствует (как это уже сделано для статических методов в java и используется библиотеками коллекции, такими как google guava)
РЕДАКТИРОВАТЬ. Используя миллимозный ответ в качестве отправной точки, я посмотрел, что такое стирание на самом деле, и оно не просто удаляет всю информацию о типе. Компилятор на самом деле немного больше (скопирован из официальный документ):
- Замените все параметры типа в родовых типах своими границами или объектом, если параметры типа не ограничены. Таким образом, полученный байт-код содержит только обычные классы, интерфейсы и методы.
- Вставьте тип при необходимости, чтобы сохранить безопасность типа.
- Создание мостовых методов для сохранения полиморфизма в расширенных общих типах.
Ответы
Ответ 1
Окончательный ответ должен был исходить от кого-то, кто разработал эту функцию, но я предполагаю, что это отличает это от использования необработанных типов, которые заставляют компилятор сделать что-то совсем другое ради совместимости. Выражение с сырым типом в нем обрабатывается тонко по-разному, чем одно, которое включает в себя дженерики, пример найден в этом вопросе SO: Общие винты с несвязанной коллекцией
Ответ 2
Разработчики Java очень стараются избегать изменения поведения существующих программ. List<String> list = new ArrayList();
выполняет компиляцию и создает необработанный ArrayList. Если к нему применен вывод типа, результат будет ArrayList<String>
, изменив его поведение и, возможно, вызовет ошибки времени выполнения в другом месте программы.
=============================================== =============================
После дальнейшего рассмотрения и комментария @millimoose, я вижу, что изменения в поведении будут локальными для инициализатора и будут обнаружены во время компиляции. Рассмотрим следующую программу:
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception {
List<Integer> integers = new ArrayList<Integer>();
integers.add(Integer.valueOf(3));
integers.add(Integer.valueOf(4));
List<String> list = new ArrayList(integers);
System.out.println(list);
}
}
Без вывода типа он запускает и печатает [3, 4]
, несмотря на нежелательную ситуацию List<String>
, которая содержит ссылки Integer.
С типом вывода он не будет компилироваться, потому что ArrayList(Collection<? extends E> c)
не позволяет использовать аргумент List<Integer>
в качестве аргумента при создании ArrayList<String>
.
Ответ 3
Полный синтаксис, требуемый компилятором java 5 и 6, следующий:
List<String> list = new ArrayList<String>();
Они решили упростить синтаксис для нас и позволить не писать параметры одного и того же типа с обеих сторон оператора присваивания. Однако оператор <>
по-прежнему должен убедиться, что вы понимаете, что вы делаете. Написав new ArrayList<>()
, вы говорите: "Я понимаю, что создаю экземпляр родового типа, а общий параметр - как один, который я указал в левой части задания".
Ответ 4
Это часть улучшения Java Generics в Java 7.
Прежде чем вам пришлось бы писать
final List<String> list = new ArrayList<String>();
Теперь вы можете написать
final List<String> list = new ArrayList<>();
Что эквивалентно - компилятор будет работать для вас. Это не то же самое, что
final List list = new ArrayList();
Что такое нетипизированный List
.
Ответ 5
Интересны случаи, когда вызов конструктора с алмазом и как rawtype успешно компилируется, но создает другой код. Такие примеры возможны при смешивании с функцией перегрузки метода. IIRC, был пример где-то в списке рассылки монеты OpenJDK (нет, я не собираюсь его искать).
Было неприемлемо, чтобы точно такой же код успешно появился на Java SE 6 и Java SE 7, но при этом получал разные результаты.
За свои деньги я бы опустил бриллиант и дал предупреждение (рассматриваем как ошибку), если бы другой код был создан алгоритмом вывода, выбранным в 7 (по сути, таким же, как для вывода метода общего типа из J2SE 5.0). Если вы написали такой код, вероятно, неясно, если он скомпилируется или нет.
Ответ 6
Если ваш проект построен на maven, добавьте ниже в pom.xml под тегом.
Он отлично работает..
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>