Ошибки компилятора с ограниченными подстановочными знаками Java

Имея следующий код:

    Stack<Integer> integers = new Stack<Integer>();
    Stack<? extends Number> numbers = integers;
    Number n = numbers.pop();
    numbers.push(3);
    numbers.push(n);

Я получаю ошибки компиляции в последних двух строках, но, хотя я немного подумал, я не понимаю, почему ошибки компиляции существуют.

The method push(capture#2-of ? extends Number) in the type Stack<capture#2-of ? extends Number> is not applicable for the arguments (int)

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

Большое спасибо


person yas4891    schedule 25.06.2011    source источник
comment
пожалуйста, проверьте другие вопросы на SO, есть много подобных вопросов.   -  person Augusto    schedule 25.06.2011
comment
Я просмотрел 5-10 из них, и они, похоже, о том, как разыгрывать List‹? расширяет Number› до List‹Integer› и т.п. хотя пойду посмотрю повнимательнее   -  person yas4891    schedule 25.06.2011


Ответы (3)


здесь очень четкий ответ Как я могу добавить в список‹? расширяет структуры данных Number›?

person Cris    schedule 25.06.2011
comment
ну иногда проще перенаправить на уже существующий хорошо документированный ответ. пожалуйста, отдайте должное этому ответу :) - person Cris; 25.06.2011
comment
alos парни отсюда, которые тратят свое время, чтобы помочь вам больше, чем я ... заслуживают этого :) - person Cris; 25.06.2011

Последние две строки недействительны, поскольку numbers может быть стеком любого числового типа. Рассмотрим этот аналогичный код:

Stack<Double> doubles = new Stack<Double>();
Stack<? extends Number> numbers = doubles;
Number n = numbers.pop();
numbers.push(3);
numbers.push(n);

Здесь вы пытаетесь поставить Integer на Stack<Double>, что явно неправильно.

По сути, когда вы используете подобные подстановочные знаки, вы можете получить значения out, но вы не можете поместить значения in, потому что компилятор не может гарантировать, что это допустимо.

person Jon Skeet    schedule 25.06.2011
comment
Прочитав это и ссылку, предоставленную @Cris, я, кажется, понял проблему. Однако почему компилятор не может определить тип, когда в стек помещается только один элемент (типа Integer)? - person yas4891; 25.06.2011
comment
@ yas4891: Компилятор предназначен для того, чтобы делать какие-либо выводы из предыдущих строк кода, а только из типа переменной, которая равна Stack<? extends Number>. - person Jon Skeet; 25.06.2011

Ковариация дженериков в Java обрабатывается на клиенте. то есть у вас нет семантики, чтобы сказать, что стек является ковариантным, и позволить компилятору проверить, что операции, которые вы разрешаете (например, push), действительны в модели ковариации. (нажима нет).

Конкретная проблема здесь в том, что вы можете сделать что-то вроде этого:

Number r = new Rational(a,b); // rationals are also numbers
number.push(r);

что в базовой структуре подразумевает integer.push(r); // несоответствие типов

(Программирование на Scala содержит кристально ясное объяснение (со-/противо-)вариантности на стороне клиента и провайдера в главе 19. Рекомендуем прочитать, даже если вы не знакомы со Scala)

person maasg    schedule 25.06.2011