Создание нового универсального объекта с подстановочным знаком
Пожалуйста, объясните этот универсальный код ошибки подстановки:
//no compile time error.
List<? extends Number> x = new ArrayList<>();
//compile time error.
List<? extends Number> x = new ArrayList<? extends Number>();
2 ответа
Недопустимый синтаксис для создания экземпляра универсального типа с подстановочными знаками. Тип List<? extends Number>
означает List
некоторого типа, который является или расширяется Number
, Создавать экземпляр этого типа не имеет смысла, потому что с помощью создания экземпляра вы создаете что-то конкретное:
new ArrayList<? extends Number>();//compiler:"Wait, what am I creating exactly?"
Универсальные типы с подстановочными знаками имеют смысл только для переменных и параметров методов, потому что это дает большую свободу в том, что может быть назначено / передано в них.
//compiler:"Okay, so passing in a List<Integer> or a List<Double> are both fine"
public void eatSomeNumbers(List<? extends Number> numbers) {
for (Number number : numbers) {
System.out.println("om nom " + number + " nom");
}
}
Обязательно учитывайте ограничения, связанные с использованием подстановочных знаков.
List<? extends Number> numList = ...
numList.add(new Integer(3));//compiler:"Nope, cause that might be a List<Double>"
Что касается вашего первого примера, diamond - это новая функция в Java 7, которая позволяет компилятору выводить тип нового универсального экземпляра на основе типа переменной, которой он назначен. В этом случае:
List<? extends Number> x = new ArrayList<>();
Компилятор скорее всего выводит new ArrayList<Number>()
здесь, но то, что выведено, вряд ли имеет значение, если это допустимое присваивание данной переменной. По этой причине был введен оператор diamond - указание универсального типа нового объекта было излишним, поскольку некоторый универсальный тип делает его допустимым присваиванием / аргументом.
Это рассуждение имеет смысл только в том случае, если вы помните, что универсальные элементы в Java являются чисто языковой функцией времени компиляции из-за стирания типов и не имеют смысла во время выполнения. Подстановочные знаки существуют только из-за этого ограничения. В отличие от этого, в C# информация универсального типа сохраняется во время выполнения - и универсальные символы подстановки не существуют на этом языке.
Использование
List<? extends Number> x = new ArrayList<Number>();
вместо.