Какова цель подстановочных знаков и как они отличаются от дженериков?

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

Предположим, у меня есть суперclass Animal и несколько подclassов, таких как Dog , Cat , Parrot и т. Д. Теперь мне нужно иметь список животных, моя первая мысль будет примерно такой:

 List listAnimals 

Вместо этого мои коллеги рекомендуют что-то вроде:

 List listAnimals 

Почему я должен использовать подстановочные знаки вместо простых дженериков?

Скажем, мне нужно иметь метод get / set, следует ли использовать первый или более поздний? Как они такие разные?

Подстановочные знаки не имеют большого смысла, когда вы объявляете локальные переменные, однако они действительно важны, когда вы объявляете параметр для метода.

Представьте, что у вас есть метод:

 int countLegs ( List< ? extends Animal > animals ) { int retVal = 0; for ( Animal cur : animals ) { retVal += cur.countLegs( ); } return retVal; } 

С помощью этой подписи вы можете сделать следующее:

 List dogs = ...; countLegs( dogs ); List cats = ...; countLegs( cats ); List zoo = ...; countLegs( zoo ); 

Если, однако, вы объявляете countLegs следующим образом:

 int countLegs ( List< Animal > animals ) 

Тогда в предыдущем примере только countLegs( zoo ) скомпилировался бы, потому что только этот вызов имеет правильный тип.

Java-дженерики являются инвариантными.

Предположим, что B extends A :

  • B является подтипом A
  • instanceof B также является instanceof A

Поскольку массивы Java ковариантны:

  • B[] является подтипом A[]
  • instanceof B[] также является instanceof A[]

Однако Java-дженерики являются инвариантными:

  • List НЕ является подтипом List
  • instanceof List не является instanceof List .

Подстановочные знаки используются для обеспечения большей гибкости при сохранении безопасности типов.

  • List – это List List

Рекомендации

  • Учебники Java / Generics
    • Подтипы
    • Больше удовольствия с подстановочными знаками

Связанные вопросы

  • Любой простой способ объяснить, почему я не могу сделать List animals = new ArrayList() ?
  • java generics (not) ковариация
  • В чем разница между и ?

Разница между двумя примерами состоит в том, что первый – это список общих / общих животных – поэтому вы можете добавить к нему любого типа животных и любой экземпляр подclassа типа Animal. (например, он может содержать некоторых собак, некоторых кошек, некоторых дикобразов …) В то время как второй – List List – будет список одного определенного подтипа classа животных. Это может быть любой, который вы выберете (это устанавливается каждый раз во время выполнения), но только один. Это будет либо список собак, либо список кошек, либо список черепах … и т. Д.

Вы можете хранить собак и кошек в List . Это не значит, что нужны маски.

Предположим, у вас есть метод, который принимает список животных:

 void foo(List animals) { ... } 

Теперь вы не можете передать метод List of Dogs – он принимает только аргумент типа List . Вам нужно подстановочный знак, чтобы заставить метод принимать все виды списков животных: List , List , List , …

 void foo(List animals) { ... } 

Видеть

http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html

  • Java Generics WildCard Вопрос: Список
  • Список файлов, не соответствующих шаблону?
  • Множественные подстановочные знаки для общих методов делают Java-компилятор (и меня!) Очень запутанным
  • Как использовать подстановочный шаблон в classpath для добавления нескольких банок?
  • Использование шаблона для открытия книги Excel
  • Обозначение MongoDB в ключе запроса
  • Как найти список файлов с помощью шаблона
  • Давайте будем гением компьютера.