HashSet包含自定义对象的问题

sri*_*har 15 java hashcode hashset

我的自定义类将由HashSet包含

public class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "hashcode='" + this.hashCode() + '\'' +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        if (!name.equals(person.name)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age;
        return result;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的HashSet测试失败了

   public void hashSetTest() {
        Set<Person>  personSet = new HashSet<Person>();
        Person p1 = new Person("raghu", 12);
        Person p2 = new Person("rimmu", 21);

        personSet.add(p1);
        personSet.add(p2);


       p1.setName("raghus");
       p1.setAge(13);

       int i2 =p1.hashCode();
       System.out.println(personSet.size() + ": "+ p1.hashCode()+" : "+personSet.contains(p1)+ " : "+i2);
    }
Run Code Online (Sandbox Code Playgroud)

我希望personSet.contains(p1)能够通过.为什么它会返回假?谢谢sri

Fre*_*Foo 29

因为p1.hashCode()修改时更改p1,所以无法再在哈希表中找到其原始索引.永远不要让哈希值依赖于可变字段.

(你很幸运,它在测试期间失败了;它可能也成功了,但只是在生产中失败.)

  • "永远"有点苛刻,因为有些情况你需要它.请记住,你必须删除这样的对象,修改它并重新添加到集合中.但显然,如果可能的话,最好只使用不可变字段. (5认同)
  • @Voo:这可能是风格和偏好的问题,但我仍然会说**永远不会**.应该根据对象的不可变部分来定义散列函数.(我会制作一个像这样的轻量级对象完全不可变,但后来我根本不喜欢setter.) (3认同)
  • 你应该将他的答案标记为正确(除了向上/向下投票之外的绿色标志). (3认同)

Mic*_*zka 5

HashSet实现了Set.ApiDoc规定:

Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.

在您的示例中就是这种情况,因为更改nameage打开p1会影响相等比较.因此,根据ApiDoc,您的案例中Set的行为未指定.