Дублирующиеся пользовательские объекты добавляются в Hashset - PullRequest
0 голосов
/ 19 апреля 2019

У меня есть класс Employee с двумя атрибутами id и name. Я переопределяю хэш-код и метод equals, как указано ниже.

Employee.java:

import java.util.Objects;

public class Employee {

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + "]";
    }
}

А теперь у меня есть тестовый класс, в котором я создаю объект класса сотрудников с именем «Chris Gayle» и добавляю его в HashSet. После этого я изменяю имя этого существующего объекта сотрудника на «Kieron Pollard» и снова добавляю этот измененный объект сотрудника в hashset.

TestSet.java

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

public class TestSet {

 public static void main(String[] args) {
     Set<Employee> hashSet = new HashSet<Employee>();

     Employee emp1 = new Employee();
     emp1.setId(1);
     emp1.setName("Chris Gayle");

     hashSet.add(emp1);

     System.out.println(hashSet);

     emp1.setName("Kieron Pollard");
     hashSet.add(emp1);
     System.out.println(hashSet.size());
     System.out.println(hashSet);
}

}

Когда я распечатываю содержимое хешсета, я даю тот же объект сотрудника два раза, как указано ниже.

[Employee [id=1, name=Chris Gayle]]
2
[Employee [id=1, name=Kieron Pollard], Employee [id=1, name=Kieron Pollard]]

Поскольку set не допускает дублирование элементов, но в выводе мы получаем дубликаты в приведенном выше сценарии. Итак, как правильно обращаться с такого рода поведением.

Ответы [ 2 ]

3 голосов
/ 19 апреля 2019

Вы застрелились здесь в ногу.

@Override
public int hashCode() {
    return Objects.hash(id, name);
}

Если hashCode определено id & name, и вы измените имя перед добавлением объекта в HashSet снова, вы, очевидно, получите дублирующую запись.Напоминание: уникальность объекта определяется hashCode - и именно это HashSet использует, чтобы определить, находится ли объект уже в Set.

Какой у вас критерий уникальности?Если id должен быть уникальным, используйте только id в hashCode.

@Override
public int hashCode() {
    return Objects.hash(id);
}
2 голосов
/ 19 апреля 2019

Спасибо, что подняли это.Вы должны посмотреть, как реализовано HashSet.Ваш пример также дает хорошее представление о том, почему предпочтительна неизменность.

Вот что происходит.

  • Вы создали объект, добавив его в HashSet.
  • HashSet хранит ссылку на объект с хешем объекта.Допустим, хэш равен 10 (для id = 1, name = Chris Gayle)
  • Теперь, когда вы меняете объект, HashSet не знает об изменениях, которые вы внесли в объект.Он содержит только ссылку, но хеш объекта изменяется.Скажем, 20 (для id = 1, name = Kieron Pollard).
  • Между равными и дэшкодом существует связь.Если хэш-коды объектов равны, объекты могут быть равны.Хеш-коды различны, тогда объекты никогда не будут равны.По этой логике HashSet добавил новую запись, когда вы добавили тот же объект или во второй раз.

Если вы попытаетесь создать новый HashSet с new HashSet<>(hashSet), вы увидите только один объект.

...