Я использую Eclipse, чтобы помочь мне очистить некоторый код для правильного использования обобщений Java. Большую часть времени он отлично справляется с выводом типов, но в некоторых случаях выводимый тип должен быть как можно более универсальным: Object. Но Eclipse, похоже, дает мне возможность выбирать между типом Object и типом «?».
Так в чем же разница между:
HashMap<String, ?> hash1;
и
HashMap<String, Object> hash2;
Ответы:
Экземпляр
HashMap<String, String>
спичек,Map<String, ?>
но нетMap<String, Object>
. Скажем, вы хотите написать метод, который принимает карты отString
s к чему-либо: если бы вы написалиВы не можете поставить
HashMap<String, String>
. Если ты пишешьоно работает!
В дженериках Java иногда неправильно понимают, что
List<String>
это не подтипList<Object>
. (НоString[]
на самом деле это подтипObject[]
, это одна из причин, по которой дженерики и массивы плохо сочетаются (массивы в Java ковариантны, дженерики - нет, они инвариантны )).Пример: если вы хотите написать метод, который принимает
List
s изInputStream
s и подтипыInputStream
, вы должны написатьКстати, «Эффективная Java» Джошуа Блоха - отличный ресурс, когда вы хотите понять не такие простые вещи в Java. (Ваш вопрос выше также очень хорошо освещен в книге.)
источник
Еще один способ думать об этой проблеме заключается в том, что
эквивалентно
Соедините эти знания с «Принципами получения и сдачи» в разделе (2.4) из Общих принципов и коллекций Java :
и можно надеяться, что дикая карта может начать иметь больше смысла.
источник
HashMap<String, ? extends Object>
так это только мешаетnull
быть добавленным в hashmap?Это легко понять, если вы помните, что
Collection<Object>
это просто универсальная коллекция, которая содержит объекты типаObject
, ноCollection<?>
является супертипом всех типов коллекций.источник
Ответы выше ковариации покрывают большинство случаев, но пропускают одно:
"?" включает в себя «Объект» в иерархии классов. Можно сказать, что String - это тип Object, а Object - это тип? Не все соответствует объекту, но все соответствует?
источник
Вы не можете безопасно вложить что-либо
Map<String, ?>
, потому что вы не знаете, какого типа должны быть значения.Вы можете поместить любой объект в
Map<String, Object>
, потому что известно, что это значениеObject
.источник
Map<String,Integer>
. ТолькоInteger
объекты должны быть сохранены на карте в качестве значений. Но так как вы не знаете тип значения (это?
), вы не знаете , если , если это безопасно звонитьput(key, "x")
,put(key, 0)
или что - нибудь еще.Объявление
hash1
какHashMap<String, ?>
диктует, что переменнаяhash1
может содержать любой,HashMap
который имеет ключString
и любой тип значения.Все вышеперечисленное является действительным, потому что переменная
map
может хранить любую из этих хэш-карт. Эта переменная не заботится о том, что представляет собой тип Value, из хеш-карты, которую он содержит.Имея подстановочные вовсе не , однако, позволяют поместить любой тип объекта в вашу карту. на самом деле, с хэш-картой выше, вы не можете поместить в нее что-либо, используя
map
переменную:Все приведенные выше вызовы методов приведут к ошибке во время компиляции, поскольку Java не знает, что такое тип Value внутри HashMap
map
.Вы все еще можете получить значение из хэш-карты. Хотя вы «не знаете тип значения» (потому что вы не знаете, какой тип хеш-карты находится внутри вашей переменной), вы можете сказать, что все является подклассом
Object
и, таким образом, все, что вы получаете из карты. будет иметь тип Object:Приведенный выше блок кода выведет 10 на консоль.
Итак, чтобы закончить, используйте
HashMap
с подстановочными знаками, когда вам все равно (то есть, это не имеет значения), какие типыHashMap
, например:В противном случае укажите типы, которые вам нужны:
В приведенном выше методе нам нужно знать, что ключ карты является a
Character
, иначе мы не знали бы, какой тип использовать для получения значений из него. Однако все объекты имеютtoString()
метод, поэтому карта может иметь любой тип объекта для своих значений. Мы все еще можем напечатать значения.источник