Подтвердить что ты не робот

Какая разница между неограниченным подстановочным типом List <?> И сырым списком типов?

Не могли бы вы помочь мне понять разницу между неограниченным типом списка подстановок и списком сырых типов?

List<?> b;    // unbounded wildcard type
List a;       // raw type


Наряду с этим может кто-нибудь помочь мне понять, что такое список параметров ограниченного типа?

List<E extends Number> c;
4b9b3361

Ответ 1

Вот краткое изложение трех:

  • List: список без параметра типа. Это список, элементы которого имеют любой тип - , элементы могут быть разных типов.

  • List<?>: Список с параметром неограниченного типа. Его элементы имеют специфический, но неизвестный тип; все элементы должны быть одного типа.

  • List<T extends E>: Список с параметром типа T. Поставляемый тип для T должен иметь тип, который расширяет E, или он не является допустимым типом для параметра.

Ответ 2

Вы действительно должны взглянуть на Эффективную Java, Пункт 23: Не использовать необработанные типы в новом коде.

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

public static int numElementsInCommon(Set s1, Set s2) {
  int result = 0;
  for (Object o : s1) {
    if (s2.contains(o)) {
      ++result;
    }
  }
  return result;
}

Этот пример, хотя он работает, не рекомендуется использовать из-за использования необработанных типов. Необработанные типы просто не безопасны для всех... вы можете в конечном итоге изменить набор таким образом, чтобы он не был безопасным и не испортил вашу программу. Вместо этого, ошибайтесь на стороне осторожности и используйте альтернативу типа безопасного типа:

public static int numElementsInCommon(Set<?> s1, Set<?> s2) {
  int result = 0;
  for (Object o : s1) {
    if (s2.contains(o)) {
      ++result;
    }
  }
  return result;
}

Разница в том, что вы можете добавить null в Set<?>, и вы НЕ МОЖЕТЕ принять что-либо о элементе, который вы вынимаете из Set<?>. Если вы используете raw Set, вы можете добавить все, что хотите. Метод numElementsInCommon является хорошим примером, когда вам даже не нужно ничего добавлять, и вам не нужно ничего принимать о том, что находится в наборе. Вот почему это хороший кандидат на использование шаблона ?.

Надеюсь, это поможет. Прочтите весь элемент в Эффективной Java, и это станет действительно понятным.

Чтобы ответить на вторую часть вашего вопроса... помните, что я сказал, когда вы используете подстановочный символ ?, вы ничего не можете принять в отношении элемента, который вы вынимаете из набора? Что делать, если вам нужно сделать предположение о интерфейсе объекта, который вы удалили из набора. Например, предположим, что вы хотите отслеживать набор Cool вещей.

public interface Cool {
  // Reports why the object is cool
  void cool();
}

Тогда у вас может быть такой код:

public static void reportCoolness(Set s) {
  for (Object item : s) {
    Cool coolItem = (Cool) item;
    coolItem.cool();
  }
}

Это не безопасный тип... вам нужно убедиться, что вы передали в набор только объекты Cool. Чтобы исправить это, вы можете сказать:

public static void reportCoolness(Set<Cool> s) {
  for (Cool coolItem : s) {
    coolItem.cool();
  }
}

Это здорово! Это именно то, что вы хотите, и безопасно. Но что, если позже у вас есть это:

public interface ReallyCool extends Cool {
  // Reports why the object is beyond cool
  void reallyCool();
}

Поскольку все ReallyCool объекты Cool, вы должны иметь возможность сделать следующее:

Set<ReallyCool> s = new HashSet<ReallyCool>();
// populate s
reportCoolness(s);

Но вы не можете этого сделать, потому что generics имеют следующее свойство: Предположим, что B является подклассом A, тогда Set<B> НЕ является подклассом Set<A>. Технический разговор для этого - "Родовые типы являются инвариантными". (В отличие от ковариантного).

Чтобы получить последний пример для работы, вам нужно создать Set<Cool> путем литья (безопасно) каждого элемента в Set<ReallyCool>. Чтобы не допустить, чтобы клиенты вашего api прошли через этот неприятный, ненужный код, вы можете просто сделать метод reportCoolness более гибким следующим образом:

public static void reportCoolness(Set<? extends Cool> s) {
  for (Cool coolItem : s) {
    coolItem.cool();
  }
}

Теперь ваш метод принимает любой Set, который содержит элементы Cool или любой подкласс Cool. Все эти типы придерживаются Cool api... поэтому мы можем безопасно вызвать метод cool() для любого элемента

Имеют смысл? Надеюсь, это поможет.

Ответ 3

В вашем первом вопросе разница между List и List<?>:

Одно существенное различие между ними состоит в том, что когда у вас есть подстановочный знак в качестве типа, тип Collection неизвестен, поэтому метод add будет вызывать ошибку времени компиляции.

Вы все еще можете получать значения из List<?>, но вам нужен явный приведение.

Ответ 4

Разница между неограниченным подстановочным знаком типа List и необработанным типом List.

Оба случая позволяют поместить в эту переменную любой тип списка:

List nothing1 = new ArrayList<String>();
List nothing2 = new ArrayList();
List nothing3 = new ArrayList<>();
List nothing4 = new ArrayList<Integer>();

List<?> wildcard1 = new ArrayList<String>();
List<?> wildcard2 = new ArrayList();
List<?> wildcard3 = new ArrayList<>();
List<?> wildcard4 = new ArrayList<Integer>();

Но какие элементы мы можем поместить в эти объекты?

Мы можем поместить только строку в List<String>:

List<String> strings = new ArrayList<>();
strings.add("A new string");

Мы можем поместить любой объект в список:

List nothing = new ArrayList<>();
nothing.add("A new string");
nothing.add(1);
nothing.add(new Object());

И мы ничего не можем (кроме нуля) поместить в List<?> ! Потому что мы используем общие. И Java знает, что это типизированный List, но не знает, какой это тип. И не позволяет нам ошибиться.

Вывод: List<?>, Который является универсальным List, дает нам безопасность типов.

PS Никогда не используйте необработанные типы в вашем коде.