Каково различие между неограниченным подстановочным списком типов<?> и необработанным списком типов?

Можно также проверить апачский проект здесь

23
задан informatik01 17 December 2016 в 00:44
поделиться

3 ответа

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

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

  • Список : список с параметром неограниченного типа. Его элементы относятся к определенному, но неизвестному типу; все элементы должны быть одного типа .

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

32
ответ дан 29 November 2019 в 01:22
поделиться

По вашему первому вопросу, разница между List и List :

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

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

4
ответ дан 29 November 2019 в 01:22
поделиться

Вам действительно стоит взглянуть на Эффективную 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 . Если вы используете необработанный набор , вы можете добавить к нему все, что захотите. Метод numElementsInCommon - хороший пример, когда вам даже не нужно ничего добавлять, и вам не нужно ничего предполагать о том, что находится в наборе. Вот почему это хороший кандидат для использования подстановочного знака ? .

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

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

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);

Но вы не можете этого сделать поскольку универсальные шаблоны обладают следующим свойством: Предположим, B является подклассом A , тогда Установить НЕ является подклассом Set . Технический разговор по этому поводу: «Универсальные типы инвариантны». (В отличие от ковариантности.)

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

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

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

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

Технический разговор по этому поводу: «Универсальные типы инвариантны». (В отличие от ковариантности.)

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

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

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

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

Технический разговор по этому поводу: «Универсальные типы инвариантны». (В отличие от ковариантности.)

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

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

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

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

(В отличие от ковариантности.)

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

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

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

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

(В отличие от ковариантности.)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

19
ответ дан 29 November 2019 в 01:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: