Создание нового универсального объекта с подстановочным знаком - PullRequest
11 голосов
/ 05 февраля 2012

Пожалуйста, объясните этот универсальный код ошибка подстановки во время компиляции:

//no compile time error.
List<? extends Number> x = new ArrayList<>(); 

//compile time error.  
List<? extends Number> x = new ArrayList<? extends Number>();

Ответы [ 2 ]

25 голосов
/ 05 февраля 2012

Недопустимый синтаксис для создания экземпляра универсального типа с подстановочными знаками. Тип 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 - указание универсального типа нового объекта было излишним, так как long некоторый универсальный тип сделает его допустимым присваиванием / аргументом.

Это рассуждение имеет смысл только в том случае, если вы помните, что дженерики в Java являются чисто языковой функцией времени компиляции из-за стирания типа и не имеют смысла во время выполнения. Подстановочные знаки существуют только из-за этого ограничения. В отличие от этого, в C # информация универсального типа сохраняется во время выполнения - и универсальные символы подстановки не существуют на этом языке.

1 голос
/ 05 февраля 2012

Используйте

 List<? extends Number> x = new ArrayList<Number>();

вместо.

...