Java Set gets duplicate entry

2020-04-23 08:30发布

JavaDoc defines set as :

A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2)

To verify the same, i created a very simple program:

import java.util.HashSet;

public class CheckHashSet {
    public static void main(String[] args) {
        HashSet<Employee> set = new HashSet<Employee>();
        set.add(new Employee(10));
        set.add(new Employee(10));
        System.out.println(set.size());
        System.out.println(new Employee(10).equals(new Employee(10)));
    }

    private static class Employee implements Comparable<Employee> {
        private final int id;
        public Employee(int id) {
            this.id = id;
        }
        @Override
        public int compareTo(Employee o) {
            return this.id - o.id; 
        }

        @Override
        public boolean equals(Object obj) {
            if(obj instanceof Employee) {
                return compareTo((Employee)obj)==0;
            }
            return false;
        }
    }
}

The output of the program is

2
true

This means new Employee(10).equals(new Employee(10)) returns true whereas set.add(new Employee(10)); set.add(new Employee(10)); adds the object twice.

What is wrong with my code?

4条回答
对你真心纯属浪费
2楼-- · 2020-04-23 09:15

Your class voilates the joint contract on equals() and hashCode():

Note that it is generally necessary to override the hashCode method whenever equals method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

In your case, equal objects do not necessarily have equal hash codes. This is what's confusing the HashSet, since Employees with the same id could end up in different buckets and consequently get treated as if they weren't equal.

To fix, override hashCode() [for example, to simply return this.id].

查看更多
干净又极端
3楼-- · 2020-04-23 09:24

Maybe here is your problem return this.id - o.id; rather you check return this.equals(o) that return true or false.

查看更多
劳资没心,怎么记你
4楼-- · 2020-04-23 09:25

Your Employee class doesn't override hashCode - it needs to do so in order for any hash-based collection to work.

For example:

@Override
public int hashCode() {
    return id;
}
查看更多
放荡不羁爱自由
5楼-- · 2020-04-23 09:29

HashSet is based on Hash Table data structure so you have to override both equals and hashCode methods in class Employee to make it work properly.

However you can use another Set implementation not based on hash table such as TreeSet.

查看更多
登录 后发表回答