TreeSet violating Set contract?

眉间皱痕 提交于 2019-12-11 04:07:41

问题


I was trying to answer this question in the forum and I found that despite of overriding the equals method in the Employee class, I am still able to add duplicate elements to the TreeSet.

The Javadoc of TreeSet.add(E) method says

Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false.

This essentially means that no 2 equals objects will be inserted into TreeSet and equality is determined solely by equals() method of contained objects.

However, below code is adding 2 elements to the Set even though they are equal

public class Employee implements Comparable<Employee> {

    String employeeName;
    int employeeId;

    public Employee(String name, int id) {
        this.employeeName = name;
        this.employeeId = id;
    }

    public int compareTo(Employee emp) {
        //return this.employeeName.compareTo(emp.employeeName);
        return (this.employeeId - emp.employeeId);
    }

    @Override
    public String toString() {
        return ("Name is: " + employeeName + " Emp id is: " + employeeId);
    }

    @Override
    public boolean equals(Object emp) {
        if(emp instanceof Employee &&((Employee)emp).employeeName.equals(this.employeeName)){
            return true;
        }
        return false;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Set<Employee> set = new TreeSet<Employee>();
        Employee e1 = new Employee("A", 1);
        Employee e2 = new Employee("A", 2);
        System.out.println(e1.equals(e2));
        set.add(e1);
        set.add(e2);
        System.out.println(set);
    }

}

And here is the output

true
[Name is: A Emp id is: 1, Name is: A Emp id is: 2]

Why is TreeSet allowing multiple elements even if they are equal?

Now I changed the compareTo method of Employee like this

public int compareTo(Employee emp) {
    return this.employeeName.compareTo(emp.employeeName);
}

And the output is

true
[Name is: A Emp id is: 1]

How the TreeSet working properly after overriding compareTo ?


回答1:


The javadoc of TreeSet also says:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

I agree that the javadoc of add() could make it clearer that equals() is not actually used, and re-state or link to this warning, though.




回答2:


Set implementations use a Map behind the scenes to manage the data and, in doing so, guarantee the uniqueness of an object through the Map's key.

As far as I know, no explicit test of equals is done meaning that your object would be added if it were not explicitly the same object (i.e. '==').

I think the docs are misleading but I guess that it's saying it's the formal language representation. It's ambiguous so I Could be wrong but I'm pretty sure that uniqueness is guaranteed by virtue of the underlying map's keys. FYI: A dummy value is passed with your object as the key.




回答3:


First thing about TreeSet is, it also maintain order of object while stroing them and use compareTo method.

Because in your first version of compareTo method you are using employeeId for comparison and put diffrent emoplyee id for object e1 and e2.

Treeset will treat this as a different object as comparison doesn't send zero value (it will send either + or - value).

but in second verion you implement compareTo using employeeName, which is same for object e1 and e2.



来源:https://stackoverflow.com/questions/17609419/treeset-violating-set-contract

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!