Что означает знак вопроса в параметре типа generics Java?
Это небольшой фрагмент кода, взятый из некоторых примеров, которые сопровождают Стэнфордский парсер. Я развиваюсь на Java около 4 лет, но никогда не имел очень сильного понимания того, что должен указывать этот стиль кода.
List<? extends HasWord> wordList = toke.tokenize();
Я не беспокоюсь о деталях кода. То, что я смущен, - это то, что, как предполагается, должно распространяться родовое выражение на английском языке.
Может кто-нибудь объяснить это мне?
Ответы
Ответ 1
? extends HasWord
означает "класс/интерфейс, расширяющий HasWord
". Другими словами, сам HasWord
или любой из его дочерних элементов... в основном все, что будет работать с instanceof HasWord
плюс null
.
В более технических терминах ? extends HasWord
? extends HasWord
является ограниченным подстановочным знаком, ? extends HasWord
31 " Эффективного Java 3-е издание", начиная со страницы 139. Та же глава из 2-го издания доступна онлайн в формате PDF; часть на ограниченных подстановочных знаках - это пункт 28, начиная со страницы 134.
Обновление: PDF-ссылка была обновлена, так как Oracle удалила ее некоторое время назад. Теперь он указывает на копию, размещенную в Университете королевы Марии при Лондонской школе электронной инженерии и компьютерных наук.
Обновление 2: давайте немного подробнее рассмотрим, почему вы хотите использовать подстановочные знаки.
Если вы объявляете метод, подпись которого ожидает, что вы передадите его в List<HasWord>
, то единственное, что вы можете передать, это List<HasWord>
.
Однако, если указанная подпись была List<? extends HasWord>
List<? extends HasWord>
тогда вы могли бы вместо этого передать List<ChildOfHasWord>
.
Обратите внимание, что существует небольшая разница между List<? extends HasWord>
List<? extends HasWord>
и List<? super HasWord>
List<? super HasWord>
. Как сказал Джошуа Блох: PECS = производитель-расширяет, потребитель-супер.
Это означает, что если вы передаете коллекцию, из которой ваш метод извлекает данные (т.е. Коллекция создает элементы для вашего метода), вы должны использовать extends
. Если вы передаете коллекцию, в которую ваш метод добавляет данные (т.е. коллекция использует элементы, которые создает ваш метод), он должен использовать super
.
Это может показаться странным. Однако вы можете увидеть это в команде sort
List
(которая является просто ярлыком для двухарговой версии Collections.sort). Вместо того, чтобы брать Comparator<T>
, он фактически берет Comparator<? super T>
Comparator<? super T>
. В этом случае Компаратор использует элементы List
, чтобы изменить порядок самого Списка.
Ответ 2
Вопросительный знак является означающим для "любого типа". ?
означает
Любой тип, расширяющийся Object
(включая Object
)
в то время как ваш пример выше означает
Любой тип, расширяющий или реализующий HasWord
(включая HasWord
if HasWord
- не абстрактный класс)
Ответ 3
List<? extends HasWord>
принимает любые конкретные классы, которые расширяют HasWord. Если у вас есть следующие классы...
public class A extends HasWord { .. }
public class B extends HasWord { .. }
public class C { .. }
public class D extends SomeOtherWord { .. }
... wordList
может ТОЛЬКО содержать список As или Bs или смесь обоих, поскольку оба класса расширяют один и тот же родительский элемент или null
(который не выполняет проверку экземпляра для HasWorld
).
Ответ 4
Возможно, придуманный пример из "реального мира" поможет.
У меня на работе есть мусорные баки, которые бывают разных вкусов. Все контейнеры содержат мусор, но некоторые контейнеры являются специализированными и не принимают все виды мусора. Итак, у нас есть Bin<CupRubbish>
и Bin<RecylcableRubbish>
. Система типов должна убедиться, что я не могу поместить свой HalfEatenSandwichRubbish
ни в один из этих типов, но он может войти в общую корзину для мусора Bin<Rubbish>
. Если бы я хотел поговорить о Bin
из Rubbish
, который может быть специализированной, так что я не могу поставить в несовместимом мусоре, то это было бы Bin<? extends Rubbish>
Bin<? extends Rubbish>
.
(Примечание: " ? extends
не означает "только чтение". Например, я могу с надлежащими мерами предосторожности вынуть кусок мусора из мусорного ведра неизвестной специальности, а затем положить его обратно в другое место.)
Не уверен, насколько это помогает. Указатель на указатель при наличии полиморфизма не совсем очевиден.
Ответ 5
На английском языке:
Это a List
некоторого типа, который расширяет класс HasWord
, включая HasWord
В общем случае ?
в generics означает любой класс. И extends SomeClass
указывает, что этот объект должен расширять SomeClass
(или быть этим классом).
Ответ 6
Значок вопроса используется для определения подстановочных знаков. Оформить документацию Oracle о них: http://docs.oracle.com/javase/tutorial/java/generics/wildcards.html