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

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

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

6 ответов

Решение

Как точка доступа, есть разница, если класс / интерфейс / конструктор / метод объявляет границу (кроме extends Object).

interface Donkey<T extends Thing> { }

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

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

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

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

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

Из экспериментов кажется, что, например, 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);}
}

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

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

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

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

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

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

Но спецификация обрабатывает их отдельно, тем не менее. Например, http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html List<?> тип reifiable, но 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,

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

<? extends Object> Точно так же, как <?>, Извините, у меня нет справки, но... это так.:)

РЕДАКТИРОВАТЬ: конечно, я думал только с определенной точки зрения, когда я сказал это. Не обращайте внимания на мой ответ (который был довольно правильно опущен) и посмотрите ответы с более высоким рейтингом для реальной истории.

Другие вопросы по тегам