以下代码应该打印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
答案 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
。情况并非如此,因为如果a
和b
具有相同的名称和相同的年龄,a.compareTo(b)
为-1,b.compareTo(a)
也为-1。因此a
同时大于b
且小于b
。
它应具有传递性:如果a < b
和b < c
,则a < c
。事实并非如此:
(a, 3) < (b, 7)
,(b, 7) < (a, 10)
(a, 3) = (a, 10)
鉴于合同未得到尊重,您无法从TreeSet中获得任何结果,而TreeSet则认为合同可以合作。
答案 3 :(得分:1)
compareTo
的实施与equals
的实施不符。 TreeSet
在compareTo
上运作。
作为旁注:hashCode()
的实施也是错误的,因为它也不符合equals
。