为什么treeset找不到这个元素?

时间:2014-01-09 09:10:08

标签: java collections

我有一个Treeset,其中人们用他们的钱分拣,但名字上是平等的。 我有杰克和杰基同名“杰基”,他们被认为是平等的。 {Tree> jack已添加到树集中,jackie不是。 contains()上的javadoc说:

  

如果此set包含指定的元素,则返回true。更多   形式上,当且仅当此集合包含元素e时才返回true   这样(o == null?e == null:o.equals(e))。

不幸的是行

System.out.println(peoples.contains(jackie));
jackie.equals(jack)返回true时,

返回false。为什么?

这是完整的代码。

public class UsingSet {


 public static void main(String[] args) {


         People jo = new People("Jo");      
         People jack = new People("Jackie");
         jack.setMoney(12);
         People jim = new People("Jimmy");
         jim.setMoney(150);
         People john = new People("John");

         TreeSet<People> peoples = new TreeSet<People>();
         peoples.add(jo);
         peoples.add(jack);
         peoples.add(jim);
         peoples.add(john);


        People jackie = new People("Jackie");
        System.out.println("equality ? "+(jackie.equals(jack)));
        System.out.println(peoples.contains(jackie));

    }
}

class People extends Object implements Comparable<People> {

    public static long maxCount() {
        return 25000000000L;
    }

    String name;
    Float  money = 1000f;

    public People(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.length());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        People other = (People) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public int compareTo(People other) {

        int result = this.money.compareTo(other.getMoney());
        if (result == 0){
            //finding a second criteria
            return this.name.compareTo(other.getName());        
        }else{
            return result;
        }
    }


    public float getMoney() {
        return money;
    }

    public void setMoney(float money) {
        this.money = money;
    }

}

编辑: javadoc表示基于自然顺序的Treeset必须与equals()保持一致compareTo()。带有Comparator的Treeset不得。

所以我稍微修改了代码:

Comparator<People> compareByMoney = new Comparator<People>() {

  @Override
  public int compare(People p1, People p2) {
    int result = p1.money.compareTo(p2.getMoney());
    if (result == 0){
    //finding a second criteria
    return p1.name.compareTo(p2.getName());     
    }else{
      return result;
    }           
}

};      

TreeSet<People> peoples = new TreeSet<People>(compareByMoney);
    ...
    System.out.println(peoples.contains(jackie)); //--> true

4 个答案:

答案 0 :(得分:1)

jackie没有正式equals来杰克,因为他们没有相同数额的钱(注意你的等号方法只检查名称,而不是钱)。

您正在使用money属性在树形图中比较它们。因为jackie有1000个钱,而jack有12个,所以它们对于树集并不相同,因此包含返回假..

如果你这样做

People jackie = new People("Jackie");
jackie.setMoney(12);

你输出两者都是真的,或者如果你的compareTo方法只是:

    @Override
    public int compareTo(People other) {
       return this.name.compareTo(other.getName());     
    }

它还会输出true

因此,您需要更改equals方法以比较money的数量,或者只使用compareTo方法中的名称。

如果您阅读了文档:

  

注意由一组维护的排序(无论是否显式   比较器提供)必须与等于一致,如果是的话   正确实现Set接口。 (参见可比较者或比较者   用于与equals一致的精确定义。)   这是因为Set接口是根据equals定义的   操作,但TreeSet实例执行所有元素比较   使用compareTo(或compare)方法,因此有两个元素   从集合的角度来看,通过这种方法认为是相等的

一致:

  

C类的自然排序据说是一致的   等于当且仅当e1.compareTo(e2)== 0具有相同的布尔值时   作为C类的每个e1和e2的e1.equals(e2)

使用您的代码:

System.out.println("equality ? "+(jackie.equals(jack))); //equality ? true
System.out.println(jackie.compareTo(jack)); //1

你班级的自然顺序与平等不一致。所以不要指望你的treeSet具有正常的行为。

答案 1 :(得分:0)

我只是运行你的代码,然后打印出“真实”

答案 2 :(得分:0)

请理解二叉树拳以了解原因

enter image description here

compareTo()方法用于在树中插入任何元素(而不是equals()方法)。 杰克和杰克有不同的金额。因此,根据compartTo()方法,两者都不是同一个对象。并且因为compareTo()方法返回false。这就是为什么contains()方法也返回false

    People jackie = new People("Jackie");
    System.out.println("equality ? "+(jackie.equals(jack)));
    System.out.println("compareTo ? "+(jackie.compareTo(jack)));
    System.out.println(peoples.contains(jackie));

如果你的equals()方法返回true,那么你的compareTo()方法也应该显示相同的行为。

答案 3 :(得分:0)

我认为您没有注意到您的算法不符合您的目的。

好的,您将jackjackie添加到TreeSet。 杰克得到name ="jackie"money="12" 杰基得到了name="jackie"money= <defaultValue> ="1000"

当你覆盖People类中的方法equals时(主要是检查2对象的名称),你通过这种方式检查了"equality ? "+(jackie.equals(jack)),这显然是真的

但是,当您在People类中覆盖方法compareTo时,首先检查两个对象之间的资金,因此您之前声明jackjackie没有相同的money属性值。实际上,它们是不同的,因为你的钱检查!= 0并且忽略了对名称的第二次检查。

好吧,如果你改变: People jackie = new People("Jackie");People jackie = new People("Jackie"); jackie.setMoney(12);

你启动它,魔术! 控制台输出:
equality ? true
true

问题解决了老兄