Какая разница между List <Object> и List <?>
Прежде, чем все вы сожжете меня живым, я должен сказать, что у меня много раз задавался этот вопрос, и я все еще не понимаю разницы между List <Object> и List <? >
Все прочитанные мной книги говорят, что в Java каждый класс является неявным подклассом Object.
Однако я увидел здесь следующий код:
public static void printList(List<Object> list) {
for (Object elem : list)
System.out.println(elem + " ");
System.out.println();
}
Этот код неправильный (намеренно для образовательных целей), и, по мнению автора, причина такова:
[...] печатает только список экземпляров объекта; он не может печатать List <Integer> , List <String> , List <Double> и т.д., поскольку они не являются подтипами List <Object>
Решение:
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
Как вы можете видеть, единственная разница - это первая строка:
public static void printList(List<Object> list) {
public static void printList(List<?> list) {
Вот почему мой вопрос: какая разница между List <Object> и List <? >
В конце концов, это суперкласс класса или нет?
Если кто-то может помочь мне с простым объяснением (я новичок в Java), я буду признателен.
Спасибо заранее.
Ответы
Ответ 1
Объяснение:
? является "подстановочным знаком". Вы можете использовать его по-разному:
неограниченный шаблон:
?
подстановочный знак с верхней границей:
? extends Object (or another class)
с нижней границей
? super Object (or another class)
Примеры:
List <?> list;
вы можете назначить list
любому списку с любым параметром типа.
List<? extends Number> list;
вы можете назначить список любого списка с типом параметра Number (или Integer, Float, ecc)
List<? super Integer> list;
вы можете назначить список любого списка с параметром типа Integer или типом в герархии типа Integer (Number, Comparable, Serializable, Object...)
Резюме:
Итак, декларация
List<Object> list;
похож на
List<? super Object> list;
потому что вы можете назначить "список" только списку объектов; то вы можете использовать список следующим образом:
list = new ArrayList<Object>();
list.add(new String(""));
list.add(new Integer(3));
Ответ 2
Одним из основных отличий является то, как вы можете изменять списки. Хорошо работает следующее:
List<Object> l1;
l1.add(new Object()); // OK
в то время как второй случай создает ошибку компиляции.
List<?> l2;
l2.add(new Object()); // Compile error
Причины этого, я думаю, несколько раз обсуждались на сайте. Короче говоря, <?>
означает a (как в одном) конкретный, но неизвестный тип. Поскольку этот тип не известен во время компиляции, вам не разрешается изменять список.
Ответ 3
То, что String
является подтипом Object
, не означает, что List<String>
является подтипом List<Object>
. Если это так, следующий код будет компилироваться:
List<String> strings = new ArrayList<String>();
List<Object> objects = strings;
objects.add((Integer) 1);
strings.get(0).charAt(0); // but the Integer 1 does not have a charAt method ...
Следовательно, List<String>
не является подтипом List<Object>
.
Оба List<String>
и List<Object>
являются подтипами List<?>
. Но поскольку List<?>
является более общим типом, вы не можете знать, какой тип принимает метод add:
List<String> strings = new ArrayList<String>();
List<?> objects = strings;
objects.add((Integer) 1); // does not compile
Ответ 4
В основном вы можете использовать обе версии аналогичным образом. Однако есть одна большая разница. Пусть объявить следующее:
List<Object> list1 = new ArrayList<Object>();
List<?> list2 = new ArrayList<String>();
Теперь попробуйте код ниже:
list1.add("");// this works fine
list2.add("");// this one issues a compile error
Кто-то может спросить, почему это. Это связано с тем, что в List<Object>
код сообщает вам, что у вас есть Object
или подтипы, но в List<?>
у вас может быть одно и то же, но вы точно не знаете. Кто-то может добавить String
или Double
, а затем попытаться прочитать и приложить к Integer
. Но опять же это невозможно.
Могут быть и другие отличия, о которых я не помню сейчас.
Ответ 5
Этот код неправильный (намеренно для образовательных целей), и, по мнению автора, причина такова:
[...] печатает только список экземпляров объекта; он не может печатать Список, список, список и т.д., Потому что они не подтипы List
Это связано с тем, что параметризованные типы инвариантны, например, для классов X и Y, List<X>
не является ни подтипом, ни супертипом List<Y>
.
Разница заключается в том, что неограниченный тип подстановок ?
означает, что тип неизвестен, и вы не можете ничего с этим поделать. A List<?>
безопасен по типу, вы не можете поместить в него какой-либо элемент, отличный от null
, и вы не можете предположить ничего о типе содержащегося в нем объекта.
List<Object>
, очевидно, означает, что List может содержать объекты любого типа.
Ответ 6
Объект - это суперкласс String, но List <Object> не является суперклассом List <String> . Если бы это было так, это было бы проблемой:
List<String> strings = ...
addObject(strings);
...
void addObjects(List<Object> objects) {
objects.add(new Object());
}
Теперь строки содержат элемент, который не является строкой.
Ответ 7
public static void main(String args[]){
List<? super Object> list=new ArrayList<>();
list.add("A");//works
List<Object> list1=new ArrayList<>();
list1.add("B");//works
List<?> list2=new ArrayList<>();
list2.add("11");//compile time error;
List<? extends Object> list4=new ArrayList<>();
list4.add("123");//compile Time error
}
Список <? расширение Object > и List <? > не позволяет добавить что-либо следовать этому, чтобы узнать причину: введите описание ссылки здесь Но, с другой стороны, List <? super Object > позволяет добавлять значения в список, потому что проблема в предоставленной ссылке не существует.