java.util.TreeSet 不遵守 Set 的无重复合同?

java.util.TreeSet not following Set's no duplication contract?

我以前在这里看到过这个问题,但从那时起我没有得到太多帮助,所以我再次提出我真正的问题。

我想根据对象的所有属性删除重复对象(此处Name, id, CompanyName, Address)。这是我的代码:

package CollectionDemo;
import java.util.TreeSet;
class Employee implements Comparable<Employee> {
    String Name;
    int id;
    String CompanyName;
    String Address;
    public Employee(String Name,int id,String CompanyName,String Address) {
        this.Name = Name;
        this.id = id;
        this.CompanyName = CompanyName;
        this.Address = Address;
    }
    @Override
    public String toString() {
        return "Name : "+this.Name+"\tID : "+this.id+"\tCompanyName : "+this.CompanyName+"\tAddress : "+this.Address;
    }
    @Override
    public int compareTo(Employee obj){
        if((this.Name.equals(obj.Name))&&(this.id==obj.id)&&(this.CompanyName.equals(obj.CompanyName))&&(this.Address.equals(obj.Address))) {
            return 0;
        }
        return 1;
    }
}

public class DemoTreeset {

    public static void main(String[] args) {
        TreeSet<Employee> ts = new TreeSet<>();
        ts.add(new Employee("Panda", 11, "Google", "California"));
        ts.add(new Employee("Panda", 12, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Google", "California"));
        ts.add(new Employee("Panda", 13, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Infosys", "India"));
        ts.add(new Employee("Panda", 11, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Infosys", "India"));
        ts.add(new Employee("Panda", 12, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Google", "California"));
        ts.add(new Employee("Panda", 13, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Infosys", "India"));
        ts.add(new Employee("Panda", 11, "Google", "California"));
        ts.add(new Employee("Panda", 11, "Infosys", "India"));
        for(Employee  e : ts) {
            System.out.println(e);
        }
    }
}

输出:

Name : Panda    ID : 11 CompanyName : Google    Address : California 
Name : Panda    ID : 12 CompanyName : Google    Address : California
Name : Panda    ID : 13 CompanyName : Google    Address : California
Name : Panda    ID : 11 CompanyName : Google    Address : California
Name : Panda    ID : 11 CompanyName : Infosys   Address : India
Name : Panda    ID : 13 CompanyName : Google    Address : California

我知道 TreeSet 使用 compareTo() 而不是 equals() 来比较对象所以我重写了它,但正如您所看到的输出,它删除了一些重复项,但不是全部。我不明白为什么我会得到这个输出。为什么不删除所有重复项,而只删除其中的几个?

当您实现由 Comparable 接口定义的契约时,您需要尊重契约要求实现的所有方面。部分遵守合同会导致奇怪的行为,就像您在您的案例中所经历的那样。 Comparable 合约的一个明显遗漏是 传递性 。来自Comparable.compareTo(...)方法的javadoc

The implementor must also ensure that the relation is transitive: (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.

您的实现绝对不是可传递的。

你能看看这个吗? 输出:

Name : Panda ID : 11 CompanyName : Google Address : California

Name : Panda ID : 12 CompanyName : Google Address : California

Name : Panda ID : 13 CompanyName : Google Address : California

Name : Panda ID : 11 CompanyName : Infosys Address : India

package algorithms;

import java.util.TreeSet;

class Employee implements Comparable<Employee> {
String Name;
int id;
String CompanyName;
String Address;

public Employee(String Name,int id,String CompanyName,String Address) {
    this.Name = Name;
    this.id = id;
    this.CompanyName = CompanyName;
    this.Address = Address;
}

@Override
public String toString() {
    return "Name : "+this.Name+"\tID : "+this.id+"\tCompanyName : "+this.CompanyName+"\tAddress : "+this.Address;
}

@Override
public int compareTo(Employee obj){
    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if (this.equals(obj)) return EQUAL;
    
    int comparison = this.Name.compareTo(obj.Name);
    if (comparison != EQUAL) return comparison;

    comparison = this.Address.compareTo(obj.Address);
    if (comparison != EQUAL) return comparison;

    comparison = this.CompanyName.compareTo(obj.CompanyName);
    if (comparison != EQUAL) return comparison;

    comparison = ((Integer)(this.id)).compareTo(obj.id);
    if (comparison != EQUAL) return comparison;

    return EQUAL;
}

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

       Employee that = (Employee)aThat;
       return
           ( this.Address.equals(that.Address)) &&
           (this.id == that.id) &&
           ( this.Name.equals(that.Name) ) &&
           ( this.CompanyName.equals(that.CompanyName) )
         ;
   }
}


public class DemoTreeSet {

public static void main(String[] args) {
    TreeSet<Employee> ts = new TreeSet<>();
    ts.add(new Employee("Panda", 11, "Google", "California"));
    ts.add(new Employee("Panda", 12, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Google", "California"));
    ts.add(new Employee("Panda", 13, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Infosys", "India"));
    ts.add(new Employee("Panda", 11, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Infosys", "India"));
    ts.add(new Employee("Panda", 12, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Google", "California"));
    ts.add(new Employee("Panda", 13, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Infosys", "India"));
    ts.add(new Employee("Panda", 11, "Google", "California"));
    ts.add(new Employee("Panda", 11, "Infosys", "India"));
    for(Employee  e : ts) {
        System.out.println(e);
    }
}

}