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

Декларация такая:

  class A<X extends Number & List> {  } 

разрешено. В то время как подобное объявление не допускается.

  class A<? extends Number & List> {  }

Есть ли какое-то логическое объяснение тому, почему Java ограничивает нас в этом?

И в чем реальная разница между

      <T extends Number>  
     & <? extends Number>?

person Debadyuti Maiti    schedule 28.03.2012    source источник
comment
У вас действительно есть класс, который расширяет Number и реализует List? Или он расширяет Number и реализует List<Number>? или X расширяет Number и реализует List<X>? Как бы вы вообще написали этот последний, не объявив где-нибудь тип X?   -  person Paul Hanbury    schedule 28.03.2012
comment
Хорошая мысль — Number и List на самом деле не те типы, которые вы ожидаете сосуществовать таким образом.   -  person Louis Wasserman    schedule 28.03.2012
comment
@LouisWasserman: Даже если они сосуществуют таким образом, я просто указал, что вам может понадобиться общее определение, чтобы указать, что содержит ваш список. В любом случае, вероятно, лучше избегать необработанного типа.   -  person Paul Hanbury    schedule 28.03.2012
comment
@PaulHanbury: они протестированы и успешно скомпилированы. Число и список взяты только для примера. Вы можете заменить их любым пользовательским именем класса, именем интерфейса. Дело в том, что подстановочный знак не разрешен в универсальном объявлении класса / метода.   -  person Debadyuti Maiti    schedule 29.03.2012
comment
@DebadyutiMaiti: По вашей логике, меня должен устроить следующий код, потому что он компилируется и проходит тесты: public class Math {public static int multiply(int x,int y){int p = 0;for(int i=0;i<x;i++) for(int j=0;j<y;j++)p++;return p;}} Меня это не устраивает. Точно так же я не думаю, что использование необработанных списков также является хорошей идеей... особенно в шаблонном классе.   -  person Paul Hanbury    schedule 19.04.2012
comment
@DebadyutiMaiti: Моя точка зрения, однако, заключалась в том, что вам нужно явно указать свой тип (например, X, а не?), Чтобы вы могли ссылаться на него в остальной части вашего кода.   -  person Paul Hanbury    schedule 19.04.2012


Ответы (3)


Весь смысл параметра типа, такого как T, заключается в том, что вы можете использовать его как тип внутри класса. Что вообще может означать подстановочный знак? Если вы не можете использовать его нигде, зачем вообще иметь параметр типа?

person newacct    schedule 28.03.2012

Если бы вы использовали <? extends Number & List>, вы не смогли бы ничего сделать с параметром типа. Это было бы совершенно бесполезно.

Точно так же ? extends Number позволяет вам иметь дело с особым случаем, когда вам не нужно ссылаться на тип, расширяющий число, и вам не нужно давать ему имя.

person Louis Wasserman    schedule 28.03.2012

Объявления универсального класса и интерфейса требуют параметров типа, таких как T или U. ? является подстановочным знаком, который лучше использовать для параметров метода, которые сами по себе являются общими:

class Foo<T extends Number & List> {
    void doStuff(List<T> items) {
        // ...
    }

    void doMoreStuff(List<? extends OutputStream> streams) {
        // ...
    }
}

doStuff() указывает, что он хочет работать с List<T>, где T — параметр типа в классе Foo. Так:

class Weird extends Number implements List {
    //
}

Foo<Weird> f = new Foo<Weird>();
f.doStuff(...);   // wants a List<Weird>

Если бы мы вызвали doMoreStuff() для f, мы могли бы передать ему что-то типа List<OutputStream>, List<FilterOutputStream>, List<ByteArrayOutputStream> и т. д.

person pholser    schedule 28.03.2012
comment
Разве ты не должен звонить doStuff() на Фу, не странно? - person John Haager; 28.03.2012