Как подстановочные знаки работают в Java

#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. Компилятору не нужна какая-либо явная информация о приведении, он автоматически разрешает правильное определение класса.