Неограниченные символы подстановки в Java
Есть ли когда-нибудь разница между неограниченным символом подстановки, например <?>
и ограниченный шаблон, чья граница Object
например, <? extends Object>
?
Я помню, как где-то читал, что в ранних версиях дженериков была разница, но я больше не могу найти этот источник.
6 ответов
Как точка доступа, есть разница, если класс / интерфейс / конструктор / метод объявляет границу (кроме extends Object
).
interface Donkey<T extends Thing> { }
...
Donkey<? extends Object> foo; // FAIL
С практической точки зрения для большинства людей, <? extends Object>
такой же как <?>
, как все предложили здесь.
Тем не менее, они отличаются двумя очень незначительными и тонкими моментами:
JVMS (спецификация виртуальной машины Java) имеет специальную спецификацию для неограниченных подстановочных знаков, как
ClassFileFormat-Java5
указывает, что неограниченный подстановочный знак кодируется как*
, в то время как кодирует объектно-ограниченный подстановочный знак как+Ljava/lang/Object;
, Такое изменение просочится через любую библиотеку, которая анализирует байт-код. Авторы компилятора должны были бы также решить эту проблему. От редакции к "Формату файла класса"С точки зрения надежности, они разные. 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>
Точно так же, как <?>
, Извините, у меня нет справки, но... это так.:)
РЕДАКТИРОВАТЬ: конечно, я думал только с определенной точки зрения, когда я сказал это. Не обращайте внимания на мой ответ (который был довольно правильно опущен) и посмотрите ответы с более высоким рейтингом для реальной истории.