2015-02-01 2 views
1

Кажется, что дубликаты разрешены в HashSets. Почему это, как я могу их удалить, и почему не работает второй remove()? Один способ удаления всех дубликатов - new HashSet<>(set), но есть ли лучший способ, который не связан с созданием нового объекта?Дубликаты в java HashSet

Set<ArrayList<String>> set = new HashSet<>(); 
ArrayList<String> a1 = new ArrayList<>(); 
ArrayList<String> a2 = new ArrayList<>(); 

a1.add("a"); 
set.add(a1); 
a1.remove("a"); 

set.add(a2); 

System.out.println(set.size()); 
System.out.println(set); 

ArrayList<String> a3 = new ArrayList<>(); 
for (Object o : set) { 
    boolean b = o.equals(a3) && (o.hashCode() == a3.hashCode()); 
    if (!b) System.out.println(false); 
} 

set.remove(new ArrayList<String>()); 
System.out.println(set); 
set.remove(new ArrayList<String>()); 
System.out.println(set); 
set.remove(set.iterator().next()); 
System.out.println(set); 
System.out.println(set.iterator().next() == a1); 

Выход: set состоит из двух одинаковых, пустых списков, и тот, который изначально не был пуст, не может быть удалено.

2 
[[], []] 
[[]] 
[[]] 
[[]] 
true 
+0

Или «полезности неизменяемых классов» ... – fge

ответ

3

Хеширование происходит при времени вставки для балансировки. Если вы впоследствии измените объект, его хэш-код изменится, но он уже будет в своем ковше. Он не будет (напрямую) извлечен, так как вы попытаетесь извлечь его с помощью хэш-кода, отличного от того, который вы использовали для его вставки.

a1.add("a"); 
set.add(a1); // hashed and bucketed 
a1.remove("a"); // hash code changes but doesn't affect set 

set.add(a2); // hashes to a different place than a1 
6

Расположение элемент хранится в HashMap зависит от hashCode этого элемента в момент его добавляют.

Если после добавления элемента вы изменяете свойство этого элемента, которое вызывает изменение его hashCode (в случае элемента ArrayList удаление этого элемента из списка делает именно это), пытаясь найти этот элемент в HashSet (или удалить его) не удастся.

1

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

Если вы хотите изменить ключ или элемент, вы должны сначала удалить его, изменить его и добавить его обратно.