HashSet позволяет несколько элементов с одинаковым HashCode - PullRequest
0 голосов
/ 03 июня 2019

Мой HashSet содержит несколько «AccessRequests» с одним и тем же HashCode. Я хочу, чтобы был только один экземпляр. Я не думал, что элементы с одинаковым HashCode могут отображаться в HashSet. Что я здесь не так делаю?

ОБНОВЛЕНИЕ: Исходя из предположения, что HashSet хранит в списке только элемент, который не равен другому, и что, возможно, мои методы equals / hash нуждались в упрощении, я обновил свою проблему. Я все еще получаю НЕСКОЛЬКО пунктов, которые оцениваются как Равные в моем HashSet.

Ниже приведены методы HashCode и Equals из AccessRequest

ОБНОВЛЕНИЕ: я обновил свой хеш и приравниваю только к тем полям, которые мне нужны, чтобы быть "равными"

    @Override
public int hashCode() {
    int hash = 5;
    hash = 79 * hash + Objects.hashCode(this.targets);
    hash = 79 * hash + Objects.hashCode(this.sources);
    hash = 79 * hash + Objects.hashCode(this.destinations);
    hash = 79 * hash + Objects.hashCode(this.services);
    hash = 79 * hash + Objects.hashCode(this.action);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final AccessRequest other = (AccessRequest) obj;
    if (!Objects.equals(this.action, other.action)) {
        return false;
    }
    if (!Objects.equals(this.targets, other.targets)) {
        return false;
    }
    if (!Objects.equals(this.sources, other.sources)) {
        return false;
    }
    if (!Objects.equals(this.destinations, other.destinations)) {
        return false;
    }
    if (!Objects.equals(this.services, other.services)) {
        return false;
    }
    return true;
}

После создания AccessRequest я сбрасываю их в HashSet и выполняю итерацию: Мой HashSet определяется следующим образом:

 Set<AccessRequest> ars = new HashSet();

       ArrayList<AccessRequest> arsAsList = new ArrayList(ars);
        for(int position=0;position<arsAsList.size();position++){
            AccessRequest fixedAR = arsAsList.get(position);
            ArrayList<AccessRequest> comparToList = new ArrayList(ars);
            for(int cPosition=0;cPosition<comparToList.size();cPosition++){
                AccessRequest nextAR = comparToList.get(cPosition);
                if(fixedAR.equals(nextAR)){
                    System.out.println("position= "+position+"  cPosition "+cPosition);
                }
            }
            System.out.println("\n Next AR");
        }

Следующий вывод:

position= 0  cPosition 0
position= 0  cPosition 5
position= 0  cPosition 6
position= 0  cPosition 14
position= 0  cPosition 24
position= 0  cPosition 32
position= 0  cPosition 39
position= 0  cPosition 40
position= 0  cPosition 43
position= 0  cPosition 77
position= 0  cPosition 96
position= 0  cPosition 97
position= 0  cPosition 99
position= 0  cPosition 109
position= 0  cPosition 111
position= 0  cPosition 115
position= 0  cPosition 173
position= 0  cPosition 182
position= 0  cPosition 187

Ответы [ 2 ]

4 голосов
/ 03 июня 2019

Наборы предотвращают дублирование на основе метода equals (1). Из Javadoc (выделено мной):

Коллекция, которая не содержит повторяющихся элементов. Более формально, в наборах нет пары элементов e1 и e2, такой что e1.equals (e2) , и не более одного нулевого элемента.

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

(1): по крайней мере HashSet, который вы используете в данный момент.

0 голосов
/ 03 июня 2019

То, что вы только что заметили, является коллизией хеш-кода.Поскольку функция хеш-кода отображает значения из большего набора (например, все возможные String, их бесконечное количество) в меньший набор (например, все возможные int, только 2 ^ 32 различных значения), всегда будут конфликты.

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

Хеш-коллизии практически неизбежны при хешировании случайного подмножества большого набора возможныхключи.Например, если 2450 ключей хэшируются в миллион сегментов, даже при совершенно равномерном случайном распределении, в соответствии с проблемой дня рождения, существует приблизительно 95% вероятность того, что по крайней мере два ключа будут хэшированы в один и тот же слот.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...