TreeSet不起作用,以下代码有什么问题?

时间:2014-08-22 14:24:04

标签: java equals compareto treeset

以下代码应该打印3个人,但实际上打印4个人,为什么? 人(" a",1)和人(" a",4)应该被视为相同,但它们不是。


import java.util.TreeSet;
public class Person implements Comparable<Person>{
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    public String name;
    public int age;

    @Override
    public int compareTo(Person o) {
        if(this.name.equals(o.name)){
            return 0;
        }else if(this.age <= o.age){
            return -1;
        }else {
            return 1;
        }
    }
    @Override public boolean equals(Object other) {
        return name.equals(((Person)other).name);
    }

    @Override public int hashCode() {
        return age * 31; 
    }
    public static void main(String[] args) {
        TreeSet<Person> persons = new TreeSet<Person>();
        persons.add(new Person("a", 1));
        persons.add(new Person("b", 3));
        persons.add(new Person("c", 2));
        persons.add(new Person("a", 4));//This should be ignored.

        /*Here should print the first 3 persons, but it prints 4 persons*/
        for(Person h: persons){
            System.out.println(h.name + ":" +h.age);
        }
    }
}

结果:
答:1个
C:2
B:3
一个:4

4 个答案:

答案 0 :(得分:4)

问题是compareTo方法,它根据年龄进行比较,但根据个人姓名确定相等,使其与自身不一致。

插入前3 Persons后,树看起来像这样(原谅可怜的ASCII艺术):

    (c,2)
      |
     /\
 (a,1) (b,3)

然后插入(a,4),基于年龄将其与(c,2)进行比较。年龄(4)大于(2),所以我们向右走。下一个比较是(b,3)。 (a,4)再次变大,因此它被添加为树的新节点(因为没有别的东西可以比较)。如果不是添加(a,4)而是添加(a,0),那么将与(a,1)进行比较,结果将是:

a:1
c:2
b:3

答案 1 :(得分:3)

使用TreeSet实现TreeMap,这是一棵红黑树。添加第一个元素时,它将成为root

(A, 1)

当你添加第二个时,它有一个不同的名字和一个更大的年龄,所以它成为了根的正确的孩子。

(A, 1)
    \
    (B, 2)

当你添加第三个时,它再次大于那些。树重新组织起来以保持平衡。

    (B, 2)
    /    \
(A, 1)  (C, 3)

然后添加最终元素。 4大于2,因此搜索沿着右侧分支向下移动并且找不到名称为&#34; a&#34;的元素,因此它会添加一个新条目。

    (B, 2)
    /    \
(A, 1)  (C, 3)
            \ 
            (A, 4)

答案 2 :(得分:3)

您的compareTo方法不尊重Comparable.compareTo()的合同。

它应该是对称的:如果是a < b,那么b > a。情况并非如此,因为如果ab具有相同的名称和相同的年龄,a.compareTo(b)为-1,b.compareTo(a)也为-1。因此a同时大于b且小于b

它应具有传递性:如果a < bb < c,则a < c。事实并非如此:

  • (a, 3) < (b, 7)
  • (b, 7) < (a, 10)
  • (a, 3) = (a, 10)

鉴于合同未得到尊重,您无法从TreeSet中获得任何结果,而TreeSet则认为合同可以合作。

答案 3 :(得分:1)

compareTo的实施与equals的实施不符。 TreeSetcompareTo上运作。

作为旁注:hashCode()的实施也是错误的,因为它也不符合equals