Неограниченные подстановочные знаки в Java

Есть ли разница между неограниченным подстановочным знаком, например. <?> и ограниченный подстановочный знак, граница которого Object, например. <? extends Object>?

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

Ответ 1

Как точка pedntry, существует разница, если класс /interface/constructor/method объявляет привязку (кроме extends Object).

interface Donkey<T extends Thing> { }

...
    Donkey<? extends Object> foo; // FAIL

Ответ 2

С практической точки зрения для большинства людей <? extends Object> совпадает с <?>, как это все предлагали здесь.

Однако они отличаются двумя очень незначительными и тонкими точками:

  • JVMS (спецификация виртуальной машины Java) имеет специальную спецификацию для неограниченных подстановочных знаков, так как ClassFileFormat-Java5 указывает, что неограниченный шаблон будет закодирован как *, в то время как кодирует ограниченный объектами подстановочный знак как +Ljava/lang/Object;. Такое изменение протекает через любую библиотеку, которая анализирует байт-код. Писателям-компиляторам тоже придется заниматься этой проблемой. Из изменений в "Формат файла класса"

  • С точки зрения reifiablity, они разные. JLS 4.6 и 4.7 кодифицируйте List<?> как тип повторного ввода, но List<? extends Object> как стираемый тип. Любой администратор библиотеки, добавляющий .isReifiable() (например, mjc lib), должен учитывать это, придерживаясь терминологии JLS. Из JLS 4.6 и 4.7.

Ответ 3

Из экспериментов кажется, что, например, List<?> и List<? extends Object> совместимы с назначением в обоих направлениях, а метод, который имеет подпись с использованием одного из них, может быть переопределен сигнатурой, использующей другую. например.

import java.util.List;

class WildcardTest<T> {
    public void foo(List<? extends T> bar) {}
}

class WildcardTest2 extends WildcardTest<Object> {
    @Override
    public void foo(List<?> bar) {super.foo(bar);}
}

Ответ 4

Это сложно...

Для любой переменной типа T спецификация говорит http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4

Каждая переменная типа... имеет границу. Если для переменной типа не объявлена ​​никакая граница, предполагается, что предполагается объект.

Можно было бы подумать, что это верно и для подстановочных знаков, а ? должно быть просто сокращением для ? extends Object.

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

Мы могли бы вывести из правил подтипирования, что List<?> и List<? extends Object> являются подтипами друг друга, то есть они в основном одного и того же типа.

Но спецификация рассматривает их отдельно. Например http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.7 List<?> является повторно идентифицируемым типом, но List<? extends Object> нет, что означает

    // ok
    List<?>[] xx = {};
    // fail
    List<? extends Object>[] yy = {};

    // ok
    boolean b1 = (y instanceof List<?>);
    // fail
    boolean b2 = (y instanceof List<? extends Object>);

Я не понимаю, почему. Кажется совершенно прекрасным сказать, что подстановочный знак должен иметь верхнюю границу и нижнюю границу, по умолчанию - Object и null type.

Ответ 5

Все в java, за исключением примитивов, расширяет Object, поэтому нет, не было бы никакой разницы. Autoboxing позволяет использовать примитивы, поэтому можно сказать, что все в java - это объект.

Ответ 6

<? extends Object> ТОЧНО совпадает с <?>. Извините, у меня нет ссылки, но... это так.:)

EDIT: конечно, я думал только с определенной точки зрения, когда я это сказал. Игнорируйте мой ответ (который был довольно правильно опущен) и посмотрите ответы с более высоким рейтингом для реальной истории.