Каковы различия между List
, List<?>
, List<T>
, List<E>
, и List<Object>
?
1. Список
List
: является необработанным типом, поэтому нет typesafe
. Он будет генерировать ошибку времени выполнения только при плохом приведении. Мы хотим, чтобы ошибка времени компиляции была плохой. Не рекомендуется использовать.
2. Список <?>
List<?>
является неограниченным символом подстановки. Но я не уверен, для чего это? Я могу напечатать List<?>
без проблем:
public static void test(List<?> list){
System.out.println(list); // Works
}
Почему я не могу добавить элементы в List<?>
?
public static void test(List<?> list){
list.add(new Long(2)); // Error
list.add("2"); // Error
System.out.println(list);
}
3. Список <T>
public static void test(List<T> list){ // T cannot be resolved
System.out.println(list);
}
Я не понимаю этот синтаксис. Я видел что-то вроде этого, и это работает:
public <T> T[] toArray(T[] a){
return a;
}
Иногда я вижу <T>
, или <E>
, или <U>
, <T,E>
. Они все одинаковые или представляют что-то другое?
4. Список <Объект>
Это дает ошибку «Метод test(List<Object>)
не применим для аргумента List<String>
»:
public static void test(List<Object> list){
System.out.println(list);
}
Если бы я попробовать это , то я получил «Не отлиты из List<String>
к List<Object>
»:
test((List<Object>) names);
Я смущен. String
является подклассом Object
, так почему не List<String>
подкласс List<Object>
?
2
. Я пишу несколько кодов, чтобы продемонстрировать это в2
. TyvmList<Object>
для?Для последней части: хотя String является подмножеством Object, но List <String> не наследуется от List <Object>.
источник
List<Object>
?Обозначение
List<?>
означает «список чего-либо (но я не говорю, что)». Поскольку кодtest
работает для любого типа объекта в списке, он работает как формальный параметр метода.Использование параметра типа (как в пункте 3) требует, чтобы параметр типа был объявлен. Синтаксис Java для этого - поставить
<T>
перед функцией. Это в точности аналогично объявлению имен формальных параметров для метода перед использованием имен в теле метода.Что касается
List<Object>
неприятия аList<String>
, это имеет смысл, потому что аString
неObject
; это подклассObject
. Исправление должно объявитьpublic static void test(List<? extends Object> set) ...
. Но тогдаextends Object
это избыточно, потому что каждый класс прямо или косвенно расширяетсяObject
.источник
List<Object>
для?List<?>
поскольку список имеет определенный, но неизвестный тип.List<Object>
будет действительно «список чего угодно», так как он действительно может содержать что угодно.Причина, по которой вы не можете использовать
List<String>
это,List<Object>
заключается в том, что это позволит вам нарушить ограниченияList<String>
.Подумайте о следующем сценарии: если у меня есть
List<String>
, он должен содержать только объекты типаString
. (Который являетсяfinal
классом)Если я могу привести это к a
List<Object>
, то это позволит мне добавитьObject
к этому списку, нарушив тем самым первоначальный контрактList<String>
.Таким образом, в общем, если класс
C
наследует от классаP
, вы не можете сказать, что онGenericType<C>
также наследует отGenericType<P>
.NB Я уже прокомментировал это в предыдущем ответе, но хотел бы расширить его.
источник
List<Object>
?List<Object>
как это побеждает назначение дженериков. Однако в некоторых случаях старый код можетList
принимать различные типы, поэтому вы можете захотеть модифицировать код, чтобы использовать параметризацию типа, чтобы избежать предупреждений компилятора для необработанных типов. (Но функциональность не изменилась)Я бы посоветовал читать головоломки Java. Он довольно хорошо объясняет наследование, обобщения, абстракции и шаблоны в объявлениях. http://www.javapuzzlers.com/
источник
Давайте поговорим о них в контексте истории Java;
List
:Список означает, что он может включать любой объект. Список был в выпуске до Java 5.0; Java 5.0 представила список для обратной совместимости.
List<?>
:?
означает неизвестный объект, а не любой объект;?
введение с подстановочными знаками предназначено для решения проблемы, построенной с использованием Generic Type; увидеть подстановочные знаки ; но это также вызывает другую проблему:List< T> List< E>
Означает обобщенную декларацию при условии отсутствия типа T или E в вашем проекте Lib.
List< Object>
означает общую параметризацию.источник
В третьем пункте, «T» не может быть разрешен, потому что он не объявлен, обычно, когда вы объявляете универсальный класс, вы можете использовать «T» в качестве имени параметра связанного типа , во многих онлайн-примерах, включая
руководства oracle,«T» используется в качестве имя параметра типа, например, вы объявляете класс как:Вы говорите, что
FooHandler's
operateOnFoo
метод ожидает переменную типа "T", которая объявлена в самом объявлении класса, с учетом этого вы можете позже добавить другой метод, такой какво всех случаях T, E или U все идентификаторы параметра типа, вы можете даже иметь более одного параметра типа, который использует синтаксис
в вашем четвертом понятии, хотя Sting является подтипом Object, в классах generics такой связи нет,
List<String>
это не подтип, посколькуList<Object>
они представляют собой два разных типа с точки зрения компилятора, это лучше всего объяснить в этой записи блога.источник
теория
String[]
может быть приведен кObject[]
но
List<String>
не может быть приведен кList<Object>
.практика
Для списков это сложнее, потому что во время компиляции тип параметра List, передаваемого методу, не проверяется. Определение метода может также сказать
List<?>
- с точки зрения компилятора это эквивалентно. Вот почему в примере 2 OP выдает ошибки времени выполнения, а не ошибки компиляции.Если вы
List<Object>
тщательно обрабатываете параметр, переданный методу, чтобы не вызывать проверку типа ни для одного элемента списка, вы можете определить свой метод с использованием,List<Object>
но фактически принятьList<String>
параметр из вызывающего кода.О. Таким образом, этот код не будет давать ошибок компиляции или времени выполнения и будет фактически (и может быть удивительно?) Работать:
B. Этот код выдаст ошибку времени выполнения:
C. Этот код выдаст ошибку времени выполнения (
java.lang.ArrayStoreException: java.util.Collections$UnmodifiableRandomAccessList Object[]
):В B параметр
set
не является типизированнымList
во время компиляции: компилятор видит его такList<?>
. Существует ошибка во время выполнения, потому что во время выполненияset
становится фактическим переданным объектомmain()
, и этоList<String>
. АList<String>
не может быть приведен кList<Object>
.В C параметр
set
требуетObject[]
. Нет ошибки компиляции и ошибки времени выполнения, когда она вызывается сString[]
объектом в качестве параметра. Это потому , чтоString[]
слепки сObject[]
. Но фактический объект, полученный,test()
остаетсяString[]
, он не изменился. Таким образом,params
объект также становитсяString[]
. И элемент 0 aString[]
не может быть присвоен aLong
!(Надеюсь, у меня все в порядке, если мои рассуждения ошибочны, я уверен, что сообщество скажет мне. ОБНОВЛЕНО: я обновил код в примере A, чтобы он фактически компилировался, при этом все еще показывая сделанную точку.)
источник
List<Object> cannot be applied to List<String>
. Вы не можете перейтиArrayList<String>
к методу, который ожидаетArrayList<Object>
.Проблема 2 в порядке, потому что "System.out.println (set);" означает «System.out.println (set.toString ());» set является экземпляром List, поэтому complier вызовет List.toString ();
Проблема 3: эти символы одинаковы, но вы можете дать им разные спецификации. Например:
Проблема 4: Коллекция не допускает ковариации параметра типа. Но массив допускает ковариацию.
источник
Вы правы: String - это подмножество Object. Поскольку String более «точен», чем Object, вы должны привести его к использованию в качестве аргумента для System.out.println ().
источник