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
)。
为了更准确, TreeSet
是SortedSet
一个实现。
如果需要.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
合同(对于任何o1
和o2
, o1.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的缺点。 例如,从集合中取出第一个项目。
希望有所帮助:-)