2015-08-29 2 views
7

я видел в нескольких разных местах людей, которые экземпляр списка или ArrayList, как:Какой тип <?> при создании списка экземпляров?

List<?> l = new ArrayList<>(); 

какой тип ?? Означает ли это, что в нем могут быть какие-либо типы? Если да, то зачем это использовать вместо простого и ArrayList?

+0

можно вставить только 'null' в' 'Список , в соответствии с [Java Учебник по неограниченными Wildcards] (https://docs.oracle.com/javase/tutorial/ java/generics/unboundedWildcards.html) –

ответ

9

Означает ли это, что оно может содержать любые типы в нем?

Нет. Это означает, что переменная l может ссылаться на список, параметризованный любым типом. Так что это фактически ограничение : вам не разрешено добавлять какие-либо объекты в l, потому что вы понятия не имеете, какие предметы он принимает. Чтобы дать конкретный пример, l может быть List<String>, или это может быть List<ExecutorService>.

+0

Таким образом, он может содержать только один тип, который вы не знаете, что это такое. Если я правильно понимаю вас, почему это может быть кому угодно? Я не вижу причины. – DITTO

+3

Это очень полезно в сигнатуре метода. Скажем, 'boolean hasPrimeNumberOfItems (Список )) --- Если вы не смогли указать шаблон, вы не смогли бы объявить подпись как общую, как вы хотите. –

+0

@MarkoTopolnik, как это отличается от метода ' (Список ))? Извините, если синтаксис немного выключен, я не использую java, но я уверен, что вы поняли мой вопрос. – dcastro

1

Как правильно указано Марко, его неизвестное ограничение на тип списка.

Документы Java говорят, что:

неограниченная тип подстановочной задаются с помощью подстановочных знаков , например, List<?> (?). Это называется списком неизвестного типа. Есть два сценария, где неограниченная подстановочные является полезным подход:

  • Если вы пишете метод, который может быть реализован с использованием функциональных возможностей, предоставляемых в классе Object.
  • Когда код использует методы в общем классе, которые не зависят от параметра типа. Например, List.size или List.clear. На самом деле, Class<?> так часто используется, потому что большинство методов в класса не зависит от Т.
+3

Попробуйте: 'Список a = new ArrayList (); a.add (1); ", а затем сравните результат с вашим вступительным заявлением. –

+0

@MarkoTopolnik: - Спасибо за указание, что.! –

1

Позвольте мне сделать это время история удлиненная кровать; прочитать его засыпает :)


Давайте начнем с этой точкой - Чтобы вызвать универсальный метод, его аргументы типа должны быть поставлены. (Если метод не вызван «необработанным» способом, то есть в стираемой форме, что является другим темой):

Например, для вызова Collections.<T>emptyList() необходимо указать T. Он может быть поставлен явно программистом -

List<String> list = Collections.<String>emptyList(); // T=String 

Но это утомительно, и вид немой. Очевидно, что в этом контексте T может быть только String. Глупо, если программист должен повторить очевидное.

Здесь Тип вывода полезен.Мы можем опустить аргумент типа, и компилятор может сделать вывод, что программист намеревается это будет

List<String> list = Collections.emptyList(); // T=String is implied 

Помните, <String> все еще подается, программист, неявно.


Возможно, программист всезнающий диктатор всех аргументов типа, и компилятор и программист есть общее понимание о том, когда аргументы типа могут быть опущены и выводимый из контекста. Когда программист опускает аргумент типа, он знает, что компилятор может вывести его точно так, как он предполагал, на основе строгого алгоритма (который он мастерит :) Это не усмотрение компилятора выбрать и выбрать аргументы типа, скорее, программист делает , и передает его компилятору.

Реалистично, умозаключение типа является настолько сложным, несколько не программист не имеет ни малейшего представления, что происходит в большинстве случаев :) Программатор больше как диктатор делает неопределенные команды, а компилятор пытается все возможное, чтобы иметь смысл из него. Мы в основном пишем код по интуиции, не обращая внимания на детали, и мы считаем, что код делает то, что мы хотим, если компилятор его одобрит.

В любом случае все аргументы типа фиксируются точно и предсказуемо во время компиляции. Любой аргумент пропущенного типа эквивалентен явно заданному.

Некоторые аргументы типа являются «неопровержимыми», например. переменная типа, введенная путем преобразования захвата. Они не могут быть явно указаны, они могут быть только выведены. (Тем не менее, программист должен знать, что они, несмотря на то, что они не могут быть названы)


В предыдущем примере, T можно сделать вывод только String, нет никаких других вариантов. Но во многих случаях есть больше кандидатов для T, и алгоритм вывода типа должен иметь стратегию для его решения одному из кандидатов. Например, рассмотрим это одинокое заявление

Collections.emptyList(); 

T может быть любого типа; T разрешен к Object, потому что, ну, нет веских оснований разрешать его на что-либо еще, например Integer или String и т. Д. Object более особенный, потому что это супертип всего.


Теперь давайте перейдем к конструкторам. Формально говоря, конструкторы не являются методами. Но они очень похожи во многих аспектах. В частности, вывод типа для конструкторов почти такой же, как и для методов. Вызов конструктора класса CLASS имеет вид new CLASS(args).

Подобно методам, конструктор может быть общим, с его собственными параметрами типа.Например,

class Bar 
{ 
    <T>Bar(T x){ .. } 

и вывода типа работает на общих конструкторах тоже

new Bar("abc"); // inferred: T=String 

Чтобы явно задать аргументы типа для конструктора,

new <String>Bar("abc"); 

Это довольно редко, хотя, что конструктор является общим ,


Генеральный конструктор отличается от общего класса! Рассмотрим это

class Foo<T> 
{ 
    Foo(T x){ .. } 

Класс является общим, конструктор - нет. Чтобы вызвать конструктор класса Foo<String>, мы делаем

new Foo<String>(""); // CLASS = Foo<String> 

типа Метода вывод что мы говорим о до сих пор не применяется здесь, потому что конструктор даже не родовой. В Java 5/6 для CLASS нет вывода типа, поэтому должно быть явно указано <String>. Это глупо, потому что <String> очевидно в этом контексте. Были обходные пути (т. Е. Использование статических заводских методов), но люди, конечно, очень расстроились и потребовали решения.


В Java 7, эта проблема решается с помощью "алмаза умозаключения" -

new Foo<>(""); // inferred: T=String 

"алмазных" относится к любопытному <> оператору. Требуется; мы не можем просто написать

 new Foo(""); 

потому, что уже имели иной смысл - вызывая конструктор «сырой» Foo.

С умозаключениями алмазов, мы можем сделать вещи, которые мы не могли бы в Java 5/6

List<Object> list = new ArrayList<>(); // Java 7. inferred: E=Object 
// equivalent to 
List<Object> list = new ArrayList<Object>(); // <Object> is required in Java 5/6 

Помните, что T=Object все еще подаются через умозаключение алмазов.


Наконец, мы возвращаемся к первоначальному вопросу

List<?> list = new ArrayList<>(); 

Здесь E=Object выводится (что еще?). Код эквивалентен

List<?> list = new ArrayList<Object>(); 

Yep, то list объект действительно является ArrayList<Object>, не ArrayList<SomethingElse>.

Также обратите внимание, что следующий будет незаконным и бессмысленные

List<?> list = new ArrayList<?>(); 
          ^^^ 

CLASS в new CLASS(args) должен быть конкретный тип. Мы можем создать экземпляр ArrayList определенного типа элемента.


Заявленный тип List<?> переменной list является слишком общим, хотя. Для локальной переменной, это лучшая практика ИМО объявить его в более конкретном типе

ArrayList<Object> list = new ArrayList<>(); 

Не используйте <?> здесь - это просто вызывает путаницу всем.

На соответствующую записку, много людей будет выступать за «программу против интерфейса»

 List<Object> list = new ArrayList<>(); 
    ^^^^ 

Это неправильно IMO. Кому мы предоставляем абстракцию в локальном блоке? Используйте наиболее специфичный тип реализации для максимальной ясности; использовать абстрактные типы в интерфейсах.


zzzzzzzzzz

+0

, когда оба класса и конструктор являются общими - http://stackoverflow.com/a/32304725/2158288 – ZhongYu

Смежные вопросы