Java TreeSet:remove和contains()不起作用 [英] Java TreeSet: remove and contains() not working

查看:521
本文介绍了Java TreeSet:remove和contains()不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have added some simple objects to a TreeSet, but when I call the TreeSet's remove() and contains() methods, they don't work. However, when I iterate over the set the object is printed. Employee objects shall be added to the set while the objects uniqueness is based on the objects name property. The Id property is the value that should be sorted, but which is not unique.

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<Employee> {

    // 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<Employee> employees = new TreeSet<Employee>(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

       } 
}


推荐答案

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

A TreeSet inserts/removes according to the results of Comparable, not .equals()/.hashCode()!

这意味着,BTW,你的<$的对象c $ c>设置执行可比较(如果他们没有,那么每次你尝试并插入一个成员时,你都会已经受到 ClassCastException )的欢迎。

This means, BTW, that the objects of your Set do implement Comparable (if they didn't, each time you'd have tried and inserted a member, you'd have been greeted with a ClassCastException).

为了更准确, TreeSet <$ c的实现$ c> SortedSet

To be more accurate, TreeSet is an implementation of SortedSet.

如果你想要 .equals() / .hashCode() -compatible set,use,例如, HashSet

If you want a .equals()/.hashCode()-compatible set, use, for instance, a HashSet.

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

For the illustration, here is what happens with BigDecimal (posted a few hours ago here):

final BigDecimal one = new BigDecimal("1");
final BigDecimal oneDotZero = new BigDecimal("1.0");

final Set<BigDecimal> hashSet = new HashSet<>();
// BigDecimal implements Comparable of itself, so we can use that
final Set<BigDecimal> 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

引用javadoc Comparable ,这意味着 BigDecimal .compareTo()与<不一致code> .equals()。

To quote the javadoc for Comparable, it means that BigDecimal's .compareTo() is "not consistent with .equals()".

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

** EDIT ** As to what the OP wants:


  • 一个集合,不接受重复的名称;

  • 集合的排序视图,它将根据用户的ID进行排序。

  • a Collection which will not accept duplicate names;
  • a sorted view of that Collection which will sort against the user's id.

如上所述,您不能拥有一个同时兼具的集合。解决方案:

As mentioned above, you cannot have one collection which does both. The solution:


  • 第一个, HashSet ;

  • 表示第二个,该副本设置为 ArrayList ,然后使用 Collections.sort()

  • for the first, a HashSet;
  • for the second, a copy of that set into an ArrayList, then using Collections.sort().

这意味着 .equals() .hashCode()必须仅对名称起作用,而自定义比较器将对该ID起作用。 比较器别无选择,只能自定义,因为它是一个与不一致的比较器.equals()无论如何。

This means .equals() and .hashCode() must act only on the name, while a custom Comparator will act on the id. The Comparator has no other choice but to be custom since it is a comparator which is not consisten with .equals() in any event.

关于建议的代码,有问题。

As to the proposed code, there are problems.

首先:员工覆盖 .equals()但不是 .hashCode()。因此, Employee 打破 .equals()合约(其中一部分是如果两个对象相等,它们必须具有相同的哈希码)。更重要的是, .hashCode()对于 HashSet 来说至关重要。修复:

First: Employee overrides .equals() but not .hashCode(). As such, Employee breaks the .equals() contract (one part of which is that if two objects are equal, they must have the same hashcode). What is more, .hashCode() is critical for HashSet to work at all. Fix:

@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);
}

第二:比较器与员工一样受损因为它打破了 Comparator 合约(对于任何 o1 o2 o1.compareTo(o2)== - o2.compareTo(o1))。修复:

Second: the comparator is equally as broken as Employee since it breaks the Comparator contract (for any o1 and o2, o1.compareTo(o2) == - o2.compareTo(o1)). Fix:

public final class EmployeeComp
    implements Comparator<Employee>
{
    @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;
    }
}

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

Then, how to obtain a sorted copy of the set:

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

DONE。

这篇关于Java TreeSet:remove和contains()不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆