#java #generics #wildcard
#java #обобщения #подстановочный знак
Вопрос:
Я читаю руководство по Java о подстановочных знаках в Generics. В следующем коде:
void printCollection(Collection<Object> c) {
for (Object e : c) {
System.out.println(e);
}
}
Означает ли это, что коллекция c
принимает type object
в качестве своих элементов, и мы не можем вызывать c.add("apple")
,
потому что «apple» — это строка, а цикл for принимает любые object
элементы из коллекции c
?
Но я не понимаю следующий код,
void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}
В этом коде используются подстановочные знаки, означающие «коллекцию, тип элемента которой соответствует чему угодно». Означает ли это, что мы можем добавлять к нему объекты любого типа, такие как c.add("string");
,
c.add(1);
, и c.add(new apple());
?
и цикл for принимает любой объект e
из коллекции c
, если c
это не object
тип, мы говорим, что элементы c
являются целыми числами. Работает ли этот код? Означает ли это, что он должен быть приведен?
Ответ №1:
Вы получили это почти в точности наоборот.
A Collection<Object>
может содержать Object
и его подклассы, и поскольку все (включая String
) является подклассом Object
, вы можете добавить что угодно в такую коллекцию. Однако вы не можете делать никаких предположений о его содержимом, за исключением того, что они Object
s.
С другой стороны, A Collection<?>
содержит только экземпляры определенного неизвестного типа (и его подклассов), но поскольку вы не знаете, к какому типу это относится, вы не можете ничего добавить (кроме null
) в такую коллекцию, равно как и делать какие-либо предположения о ее содержимом (за исключением того, что это Object
s, потому что все есть).
Ответ №2:
В часто задаваемых вопросах по Java Generics от Анжелики Лангер, вопрос «В чем разница между неограниченным параметризованным типом с подстановочными знаками и необработанным типом?» (ссылка) вы увидите, что Collection<?>
и Collection<Object>
почти эквивалентны.
Комментарии:
1. Они вообще не эквивалентны, когда дело доходит до добавления к ним чего-либо.
Ответ №3:
В случае второго оператора подстановочный знак «?» означает, что обобщенный код не определен. В результате тип привязывается к «Object», потому что это привязка по умолчанию для отсутствия объявления.
На самом деле даже «Integer» является подклассом Object. Если вы имеете в виду «int», вы правы, это примитив, а не производное от Object , но вы не можете поместить его в коллекцию, поскольку коллекция допускает только производные от Object .
И к вопросу, должны ли элементы, помещенные в коллекцию, быть приведены. Нет, в этом нет необходимости, поскольку они являются классами, производными от Object. Компилятору не нужна какая-либо явная информация о приведении, он автоматически разрешает правильное определение класса.