Почему оператор ромба используется для вывода типа в Java 7?

List<String> list = new ArrayList(); приведет к предупреждению компилятора.

Однако следующий пример компилируется без предупреждения: List<String> list = new ArrayList<>();

Мне любопытно, зачем вообще нужен ввод алмазного оператора. Почему бы просто не сделать вывод типа в конструкторе, если аргумент типа отсутствует (как это уже было сделано для статических методов в java и использовалось библиотеками коллекций, такими как google guava)

РЕДАКТИРОВАТЬ: Используя миллимус ответ в качестве отправной точки, я посмотрел, что на самом деле стирание типов, и это не просто удаление всей информации о типах. Компилятор на самом деле делает немного больше (скопировано из официального документа):

  • Замените все параметры типа в универсальных типах их границами или Object, если параметры типа не ограничены. Таким образом, полученный байт-код содержит только обычные классы, интерфейсы и методы.
  • Вставьте слепки типа, если необходимо, чтобы сохранить безопасность типов.
  • Генерация мостовых методов для сохранения полиморфизма в расширенных универсальных типах.

6 ответов

Решение

Окончательный ответ должен был прийти от того, кто разработал эту функцию, но я предполагаю, что она должна отличать это от использования необработанных типов, которые заставляют компилятор делать что-то совсем другое для совместимости. Выражение с необработанным типом в нем обрабатывается несколько иначе, чем с использованием обобщений, пример можно найти в этом вопросе SO: Общий сбивает несвязанную коллекцию

Разработчики 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> который содержит целочисленные ссылки.

С выводом типа он не будет компилироваться, потому что ArrayList(Collection<? extends E> c) не позволяет использовать List<Integer> в качестве аргумента при создании ArrayList<String>,

Полный синтаксис, требуемый компилятором Java 5 и 6:

List<String> list = new ArrayList<String>();

Они решили упростить для нас синтаксис и позволить не записывать одинаковые параметры типа по обе стороны от оператора присваивания. Тем не менее <> Оператор по-прежнему обязан убедиться, что вы понимаете, что вы делаете. Письменно new ArrayList<>() Вы говорите: "Я понимаю, что я создаю экземпляр универсального типа, а универсальный параметр такой же, какой я объявил в левой части назначения".

Это является частью улучшения Java Generics в Java 7.
Прежде чем вы должны были написать

final List<String> list = new ArrayList<String>();

Теперь вы можете написать

final List<String> list = new ArrayList<>();

Что эквивалентно - компилятор решит это за вас. Это не то же самое, что

final List list = new ArrayList();

Какой нетипизированный List,

Интересны случаи, когда вызов конструктора с помощью diamond и в виде rawtype успешно компилируется, но создает другой код. Такие примеры возможны при смешивании с функцией перегрузки метода. IIRC, где-то в списке рассылки монет OpenJDK был пример (нет, я не буду пытаться его найти).

Было недопустимо, чтобы на Java SE 6 и Java SE 7 был успешно установлен точно такой же код, но были получены разные результаты.

За мои деньги я бы опустил бриллиант и получил бы предупреждение (считалось ошибкой), если бы алгоритм, определяемый в 7, генерировал бы другой код (по сути, такой же, как и для вывода универсального типа метода из J2SE 5.0). Если вы написали такой код, вероятно, неясно, будет ли он компилируемым или нет.

Если ваш проект построен на 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>

Другие вопросы по тегам