В этой статье мы разберемся что значит знак вопроса в Set<?>
. Такая запись означает, что множество может содержать элементы любого типа, но и просто Set
может содержать элементы любого типа — так в чем же разница между ними?
Особенности использования Set<?>
Известно, что множество Set<?>
может содержать внутри любой тип элементов, но идея в том, что мы не можем добавлять в него элементы. На первый взгляд эти два факта противоречат друг другу, однако давайте посмотрим на простом примере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public static void main(String[] args) { // создаем две коллекции, которые принимают объекты разных типов: HashSet<Integer> setOfIntegers = new HashSet<Integer>(Arrays.asList(4, 5, 6)); print(s1); HashSet<String> setOfStrings = new HashSet<String>(Arrays.asList("e", f", "j")); print(s2); } //метод для печати элементов коллекции public static void print(Set<?> s) { for (Object o : s) { System.out.println(o); } } |
Давайте проанализируем код выше:
Зная тот факт, что Set<?>
может принимать любой тип элементов, мы просто используем объект типа Object для того, чтобы обойти все элементы множества.
Теперь рассмотрим такую ситуацию:
1 2 3 4 5 6 7 |
public static void changeSet(Set<?> set) { // пробуем добавить элемент в множество Set<?> set.add(8); // → здесь будет ошибка for (Object o : s) { System.out.println(o); } } |
В методе changeSet()
множество определено как <?>
, а это значит, что мы точно не знаем данные какого типа в нем есть, следовательно мы ничего в это множество добавить не можем. Исключение составляет лишь null.
Если переписать представленный выше метод в виде:
1 2 3 4 5 6 7 |
public static void changeSet(Set set) { // пробуем добавить элемент в множество Set set.add("8"); // --> здесь все хорошо добавится for (Object o : s) { System.out.println(o); } } |
Множество Set не имеет таких ограничений. Однако используя такой подход может привести к возможным ошибкам в дальнейшем.
Где использовать Set<?>
и чем он полезен?
Давайте рассмотрим случай когда Set<?>
реально полезен:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static void main(String[] args) { HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(1,2,3)); HashSet<Integer> set2 = new HashSet<Integer>(Arrays.asList(4,2,3)); System.out.println(getUnion(s1, s2)); } public static int getUnion(Set<?> set, Set<?> set2){ int count = set.size(); for(Object o : set2){ if(!set.contains(o)){ count++; } } return count; } |
Как видите, Set<?>
полезен в утилитных методах, которые как-то обрабатывают элементы множества, не изменяя саму колекцию.
Если Вы хотите использовать родовые типы, но не знаете фактический тип коллекции, то Set<?>
также Ваш выбор.