Неограниченные символы подстановки в Java - PullRequest
19 голосов
/ 06 января 2010

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

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

Ответы [ 6 ]

32 голосов
/ 07 января 2010

С практической точки зрения для большинства людей, <? 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 .

18 голосов
/ 07 января 2010

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

interface Donkey<T extends Thing> { }

...
    Donkey<? extends Object> foo; // FAIL
4 голосов
/ 06 января 2010

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

Сложно ...

Для любой переменной типа 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<?> - это тип 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.

0 голосов
/ 07 января 2010

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

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

0 голосов
/ 06 января 2010

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

...