Java TreeSet:remove和contains()不起作用

我已经向TreeSet添加了一些简单的对象,但是当我调用TreeSet的remove()和contains()方法时,它们不起作用。 但是,当我遍历集合时,会打印对象。 当对象唯一性基于对象名称属性时,应将Employee对象添加到集合中。 Id属性是应该排序的值,但不是唯一的。

public class Employee { private String name; private int id; 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; } // Two objects are considered equal if their names are equal @Override public boolean equals(Object o) { if (o == null) return false; if (this == o) return true; if (o.getClass() == this.getClass()) { Employee p = ( Employee) o; if (p.getName() != null && this.getName() != null) return this.getName().equals(p.getName()); else return false; } else { return false; } } } //******************************************************* public class EmployeeComp implements Comparator { // Sort Ids, but allow duplicates, hence this function is never returning 0 @Override public int compare(Employee p1, Employee p2) { int re = 0; boolean scoreLt = (p1.getId() > p2.getId()); boolean scoreGt = (p1.getId() < p2.getId()); if(scoreLt) re = -1; if(scoreGt) re = 1; else re = -1; return re; } } //******************************************************* // Collection shall store unique names with ordered values like: // Alex, 923 // Toni, 728 // Eddi, 232 // Peter, 232 // Eddi, 156 *** not allowed import java.util.TreeSet; public class Main { private static EmployeeComp comp = new EmployeeComp(); private static TreeSet employees = new TreeSet(comp); public static void main(String[] args) { Employee p1 = new Employee(); p1.setName("Eddi"); p1.setId(232); Employee p2 = new Employee(); p2.setName("Toni"); p2.setId(728); Employee p3 = new Employee(); p3.setName("Peter"); p3.setId(232); Employee p4 = new Employee(); p4.setName("Alex"); p4.setId(923); employees.add(p1); employees.add(p2); employees.add(p3); employees.add(p4); // Here, contains() and remove() should check the object address // and not perform their actions based on compareTo } } 

TreeSet 根据Comparable的结果插入/删除,而不是.equals() / .hashCode()

这意味着BTW,你的Set的对象实现了Comparable (如果他们没有,那么每次你尝试并插入一个成员时,你都会遇到ClassCastException )。

为了更准确, TreeSetSortedSet一个实现。

如果需要.equals() / .hashCode()兼容设置,请使用例如HashSet

为了说明,这里是BigDecimal发生的事情(几个小时前在这里发布 ):

 final BigDecimal one = new BigDecimal("1"); final BigDecimal oneDotZero = new BigDecimal("1.0"); final Set hashSet = new HashSet<>(); // BigDecimal implements Comparable of itself, so we can use that final Set treeSet = new TreeSet<>(); hashSet.add(one); hashSet.add(oneDotZero); // hashSet's size is 2: one.equals(oneDotZero) == false treeSet.add(one); treeSet.add(oneDotZero); // treeSet's size is... 1! one.compareTo(oneDotZero) == 0 

引用Comparable的javadoc,意味着BigDecimal.compareTo() “与.equals()不一致”。

**编辑**关于OP想要什么:

  • 不接受重复名称的Collection ;
  • Collection的排序视图,将根据用户的id进行排序。

如上所述, 您不能拥有一个同时执行这两者的集合 。 解决方案:

  • 第一个是HashSet ;
  • 对于第二个,将其设置为ArrayList的副本,然后使用Collections.sort()

这意味着.equals().hashCode()必须仅对名称起作用,而自定义Comparator将对id起作用。 Comparator别无选择,只能自定义,因为它是一个比较器,在任何情况下都不符合.equals()

至于提议的代码,存在问题。

第一: Employee覆盖.equals()但不覆盖.hashCode() 。 因此, Employee中断了.equals()契约(其中一部分是如果两个对象相等,则它们必须具有相同的哈希码)。 更重要的是, .hashCode()HashSet起作用至关重要。 固定:

 @Override public int hashCode() { return name == null ? 0 : name.hashCode(); } @Override public boolean equals(final Object obj) { if (obj == null) return false; if (this == obj) return false; if (!(obj instanceof Employee)) return false; final Employee other = (Employee) obj; return name == null ? other.name == null : name.equals(other.name); } 

第二:比较器与Employee一样破碎,因为它打破了Comparator合同(对于任何o1o2o1.compareTo(o2) == - o2.compareTo(o1) )。 固定:

 public final class EmployeeComp implements Comparator { @Override public int compare(final Employee o1, final Employee o2) { final int id1 = o1.getId(), id2 = o2.getId(); if (id1 == id2) return 0; return id1 > id2 ? 1 : -1; } } 

然后,如何获取该集的排序副本:

 // "set" contains the unique employees final List sorted = new ArrayList(set); Collections.sort(list, new EmployeeComp()); 

DONE。

你的问题是概念性的。

如果需要已排序的唯一对象集合:TreeSet
如果您想要一个已排序的集合,则不同的对象可以具有相同的比较值以进行排序: PriorityQueue

顺便提一下,PriorityList中的方法比TreeSet上的方法更适合第二种情况的通常需要。 我曾经认为它是TreeSet的缺点。 例如,从集合中取出第一个项目。

希望有所帮助:-)