请告诉我这里发生了什么问题。我有一个Person
类,我在TreeMap中使用它作为键。我也实现了Comparable
,以便TreeMap
可以进行排序。
public class Person implements Comparable{
private String name;
private int age;
// getters and setters were omitted
@Override
public int compareTo(Object o) {
return 0;
}
}
现在我创建了TreeMap
并在其中添加了值:
Map treeMap=new TreeMap<Person,Object>();
treeMap.put(new Person(), "String1");
treeMap.put(new Person(), "String2");
treeMap.put(new Person(), "String3");
treeMap.put(new Person(), "String4");
System.out.println(treeMap);
使用System.out.println(treeMap);
Iam直接打印后,只获取最后插入的值,即
输出: {Person@4aa36c=String4}
我知道键应该是不同的但是新操作符总是创建一个新对象所以我认为它很好。但我无法弄清楚这里发生了什么问题。
答案 0 :(得分:2)
您可能会向后放置Map中的项目,并且很可能希望将Person
对象作为值,将String作为键。但首先,您需要使用构造函数增强Person对象,以允许您至少设置名称,也可以设置年龄。将构造函数添加到“Person”:
public Person(String n, int a){
this.name = n;
this.age = a;
}
然后,您可以重新排序向地图添加元素的方式:
Person p1 = new Person("Bob Jones", 32);
treeMap.put(p1.getName(), person);
此外,TreeMap
使用compareTo
方法确定将条目放在地图中的位置。因此,如果您打算使用Person对象作为键,则需要实现compareTo方法。但是你的compareTo
方法没有正确实现,只是为每个元素返回0,导致你的元素覆盖Map中的每个其他位置:
@Override
public int compareTo(Object o) {
/ TODO Auto-generated method stub
return 0;
}
您需要正确实现方法内容(因此TODO语句)。
可能会在Person类中添加社会安全号码(SSN):
Long ssn;
public void setSsn(Long value){
ssn = value;
}
public Long getSsn(){
return ssn;
}
然后你可以在ssn上进行比较:
@Override
public int compareTo(Object o) {
if(o == null) return 1;
Person op = (Person)o;
return ssn.compareTo(op.getSsn());
}
但是如果你只是想用你所拥有的东西创建某种类型的组合,可以连接名称和年龄以尝试具有唯一性:
@Override
public int compareTo(Object o) {
if(o == null) return 1;
Person op = (Person)o;
return (name + age).compareTo(op.getName() + op.getAge());
}
答案 1 :(得分:2)
您错误地覆盖了toCompare
方法。它总是返回0
。因此,树中的所有对象都将被解释为相同,而treeMap
始终只包含最后添加的值。
我建议你考虑一下紧凑的(但不是一般的@ 4castle注意到的)解决方案。
@Override
public int compareTo(Person o) {
if (age != o.age) return age > o.age ? 1 : -1;
return name.compareTo(o.name);
}
如果您将类声明的第一行更改为
public class Person implements Comparable<Pesron>
答案 2 :(得分:2)
TreeMap
在compareTo
尝试将Comparable
元素转换为{equals
时使用Object
put
方法的Map
方法1}}。由于compareTo
方法实现会为所有0
个对象返回Person
,因此TreeMap
中只能有一个元素。
因此,当您尝试放置多个Person
个密钥时,TreeMap
仅更新值,因为所有Person
个对象都相同(根据您对compareTo
的实现)
以下是来自Java-8
的TreeMap.put
的代码段
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
首先检查是否提供Comparator
,如果是,TreeMap
使用compare
方法比较密钥,否则使用compareTo
方法Comparable
为了比较。
答案 3 :(得分:0)
根据内存地址,密钥并不是唯一的,它们基于具有唯一值而是唯一的。您的所有Person
个对象几乎相同,但更重要的是,您的所有Person
个对象声称是&#34;等于&#34;给定当前Person
实现的任何其他compareTo
对象(0表示相等)。
put
方法的参数顺序首先是键,值是秒。您需要重新排列put
语句,以便在前面有一些独特的内容(字符串),从而使所有条目都是唯一的。
treeMap.put("String1", new Person());
treeMap.put("String2", new Person());
treeMap.put("String3", new Person());
treeMap.put("String4", new Person());
现在无需在Comparable
中实施compareTo
或Person
方法。
如果您要求Person
对象为密钥,则必须通过为其提供唯一变量来使每个变量唯一,以便使用compareTo
方法正常。最佳解决方案是为每个Person
对象添加所需的ID号,或者使用name
和age
作为对象的唯一值。将此代码添加到Person
:
private int id;
private static int numPeople = 0;
public Person() {
numPeople++;
id = numPeople;
name = "";
}
@Override
public int compareTo(Person o) {
if (age != o.age) return age > o.age ? 1 : -1;
if (!name.equals(o.name) return name.compareTo(o.name);
return id > o.id ? 1 : -1;
}
与
public class Person implements Comparable<Person>