Что означает знак вопроса в параметре типа 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 (или быть этим классом).