Дублировать элементы в java.util.Set

java.util.Set реализация удаляет повторяющиеся элементы.

Как элементы дубликатов удаляются изнутри в java.util.Set

Ответ 1

На самом деле AFAIK из источников в большинстве реализаций Set в java даже не проверяет, содержится ли этот элемент.

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

например. HashSet вызывает put(K,V) во внутреннем HashMap, который просто вставляет новый объект, перезаписывая старую запись, если дубликат.

Ответ 2

Внимательно прочитав ваш вопрос, я предполагаю, что вы видите странное поведение с java.util.HashSet (как правило, все по умолчанию используют).

В соответствии с контрактом java.util.Set можно получить один и тот же объект в java.util.HashSet в два раза:

import java.util.HashSet;
import java.util.Set;

public class SetTest 
{
  public static void main(String[] args) 
  {
    MyClass myObject = new MyClass(1, "testing 1 2 3");

    Set<MyClass> set = new HashSet<MyClass>();
    set.add(myObject);

    myObject.setHashCode(2);
    set.add(myObject);

    System.out.println(set.size());  // this will print 2.
  }

  private static class MyClass 
  {
    private int hashCode;
    private String otherField;

    public MyClass(int hashCode, String otherField) 
    {    
      this.hashCode = hashCode;
      this.otherField = otherField;
    }

    public void setHashCode(int hashCode) 
    {
      this.hashCode = hashCode;
    }

    public boolean equals(Object obj) 
    {    
      return obj != null && obj.getClass().equals(getClass()) && ((MyClass)obj).otherField.equals(otherField);
    }

    public int hashCode() 
    {
      return hashCode;
    }
  }
}

После указателя из @jitter и взгляда на источник вы можете понять, почему это произойдет.

Как и @jitter, java.util.HashSet использует java.util.HashMap внутренне. Когда хеш изменяется между первым и вторым, в java.util.HashMap используется другое ведро, и объект находится в наборе дважды.

Пример кода может выглядеть немного уверенным, но я видел, как это происходит в дикой природе с доменами, где хэш создается из изменяемых полей, и метод equals не синхронизирован с этими полями.

Ответ 3

Легкий способ узнать это - посмотреть в источнике кода, который вас интересует.

В каждом JDK включен src.zip, который содержит исходный код для общедоступных классов, поэтому вы можете просто найти источник для HashSet и посмотреть:) Я часто использую Eclipse для этого. Запустите его, создайте новый Java-проект, установите JVM как установленный JDK (если вы не используете JRE, установленный по умолчанию, который не имеет src.zip) и Ctrl-Shift-T, чтобы перейти к HashSet.

Ответ 4

Подробнее читайте ваш вопрос:

Вы не можете добавлять дубликаты из java doc для Set.add() или вы имеете в виду addAll?:

Добавляет указанный элемент к этому набору, если он еще не присутствует (дополнительная операция). Более формально добавляет указанный элемент e к этому набору, если в наборе нет элемента e2, такого, что (e == null? E2 == null: e.equals(e2)). Если этот набор уже содержит элемент, вызов оставляет его неизменным и возвращает false. В сочетании с ограничением на конструкторы это гарантирует, что множества никогда не содержат повторяющихся элементов.