Разница между несвязанным подстановочным знаком и необработанным типом
Я читал о дженериках, и я не понимал необходимости для несвязанных подстановочных знаков и того, как он отличается от необработанного типа. Я прочитал этот вопрос, но все еще не понял его. На странице Java tutorial для несвязанного подстановочного знака я получил ниже двух пунктов, и я не понял первого пункта:
- Если вы пишете метод, который может быть реализован с использованием функциональных возможностей, предоставляемых в классе
Object
. - Когда код использует методы в общем классе, которые не зависят от параметра типа. Например,
List.size()
или List.clear()
. На самом деле, Class<?>
так часто используется, потому что большинство методов из Class<T>
не зависят от T
.
Может кто-то объяснит разницу между несвязанным подстановочным знаком и необработанным типом на языке неспециалиста.
Как List<?>
отличается от List<Object>
?
Ответы
Ответ 1
Как List<?>
отличается от List<Object>
Основное отличие состоит в том, что первая строка компилируется, а вторая не делает:
List<?> list = new ArrayList<String> ();
List<Object> list = new ArrayList<String> ();
Однако, поскольку вы не знаете, что такое общий тип List<?>
, вы не можете использовать его параметризованные методы:
List<?> list = new ArrayList<String> ();
list.add("aString"); //does not compile - we don't know it is a List<String>
list.clear(); //this is fine, does not depend on the generic parameter type
Что касается разницы с необработанными типами (без дженериков), код ниже компилируется и работает нормально:
List list = new ArrayList<String> ();
list.add("aString");
list.add(10);
Ответ 2
Как List<?>
отличается от List<Object>
?
List<Object> l1 = new ArrayList();
List<?> l2 = new ArrayList();
l1.add("Object");
//l2.add("Object"); incorrect
l2.add(null);
Вы можете добавить только нулевое значение в List<?>
Ответ 3
Лично я нашел эту дополнительную ссылку из учебника Java по шаблонам.
Одно из основных различий, которое я вижу между List<?>
и List
, состоит в том, что первое может быть полезно только для чтения из него элементов (если вы действительно не хотите добавить null
), последний позволяет (не отмечен) добавление к нему произвольно типизированных объектов с возможными неожиданными побочными эффектами.
Ответ 4
Список полезен в сигнатуре метода для вызова методов, которые никогда не требуют параметра типа, то есть, читаются из списка или, например, вращают его.
void someMethod(List<?> list) {
list.clear(); // I will never add anything to the list in here
}
Вы никогда не будете добавлять что-либо или иным образом изменять список в отношении типа, который он содержит, поскольку вы не можете добавить что-либо в список, кроме null в методах с этой сигнатурой, и, таким образом, вы никогда не нарушите безопасность типа.
Raw List, с другой стороны, вы можете сделать что угодно, что, как мы все знаем, может привести к нарушению безопасности типа.
void someMethod2(List list) {
list.add(new WeaselFurBrush());
}
List list1 = new ArrayList<String>();
someMethod2(list1);// oops