当插入重复键时,我对Java HashMap有一个非常基本的疑问。
我的目的是创建4个Emp对象。 2对象(e1和e2)具有相同的hashCode。因此,当插入e1(在e2之后插入)时,hashmap将意识到已经存在具有相同散列值的对象(对象e2)。然后,它将使用相同的散列值比较插槽中所有对象的键。如果它找到一个具有匹配键的对象(通过调用下面的Emp类的equals方法),它将用新值替换旧值。
请查看下面的测试代码:
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
class Emp {
String name;
int age;
public Emp(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object s) {
if(s instanceof Emp) {
Emp s1 = (Emp) s;
return ((s1.name.compareToIgnoreCase(this.name) == 0));
}
return false;
}
public int hashCode() {
//return (this.name.hashCode() + this.age);
return this.name.hashCode();
}
}
public class HashTest {
public static void main(String[] args) {
Emp e1 = new Emp("Terry", 26);
Emp e2 = new Emp("Terry" , 60);
Emp e3 = new Emp("John", 21);
Emp e4 = new Emp("Test", 60);
Map<Emp,Emp> emp = new HashMap<Emp, Emp>();
emp.put(e2,e2);
Emp v2 = emp.put(e1,e1);
emp.put(e3,e3);
emp.put(e4,e4);
System.out.println("Replaced Record Name: " + v2.name + " , age: " + v2.age);
for(Emp e: emp.keySet())
System.out.println("Name: " + e.name + " , age: " + e.age);
}
}
我期待的输出: 替换记录名称:Terry,年龄:60 姓名:考试,年龄:60岁 姓名:特里,年龄:26 姓名:约翰,年龄:21
我得到的输出: 替换记录名称:Terry,年龄:60 姓名:考试,年龄:60岁 姓名:特里,年龄:60 姓名:约翰,年龄:21
我期待(Terry,60岁)被(Terry,26)对象取代。这似乎正在发生,因为我得到替换记录名称:Terry,年龄:60 作为输出。但是,地图中包含记录名称:Terry,年龄:60 而不是姓名:Terry,年龄:26 。
编辑:感谢大家的建议。事实证明我犯了一个非常粗心的错误。我打印的只是键,而不是打印与键相关的值。
正如大家所指出的,解决方案是:
for(Emp e: emp.keySet())
{
Emp empVal = emp.get(e);
System.out.println("Name: " + empVal.name + " , age: " + empVal.age);
}
答案 0 :(得分:2)
您的输出是打印键,而不是值。在您的代码中,密钥不会改变,但值将会改变。
例如,如果将输出循环更改为:
for (Emp emp : emp.values()) {
System.out.println("Name: " + e.name + " , age: " + e.age);
}
我怀疑你会看到你期待的答案。
然而:总的来说,我建议不要做你在这做的事情。所有类型的代码都希望如果a.equals(b)
那么a
和b
根本没有任何有意义的差异,那么Emp
类的equals
实现就没有了不辜负那份合同。例如,如果您使用的是HashSet
而不是HashMap
,那么您将获得更多特殊行为,并且无法修复它。
实现此方法的更好方法可能是让Emp
的{{1}}和hashCode
方法正确尊重名称和年龄,并使您的地图成为equals
关键是员工的姓名,值为Map<String, Emp>
记录。
答案 1 :(得分:0)
我稍微修改了你的代码 - 见下文。新值放在地图中,但由于键是等号,第二个put会重用现有键。
public static void main(String[] args) {
Emp e1 = new Emp("Terry", 26);
Emp e2 = new Emp("Terry", 60);
Map<Emp, Emp> emp = new HashMap<Emp, Emp>();
emp.put(e2, e2);
Emp v2 = emp.put(e1, e1);
System.out.println("Replaced Record Name: " + v2.name + " , age: " + v2.age);
for (Emp e : emp.keySet()) {
System.out.println("[key] Name: " + e.name + " , age: " + e.age);
System.out.println("[value] Name: " + emp.get(e).name + " , age: " + emp.get(e).age);
}
}
输出:
[key] Name: Terry , age: 60
[value] Name: Terry , age: 26
答案 2 :(得分:0)
在下面的语句中,您实际上正在打印密钥..通过调用keySet()
,您可以在Set
中获得map
个密钥,然后迭代这些密钥并打印它们。你需要从map中获取这些键的值并打印它们。所以,改变下面的语句: -
System.out.println("Name: " + e.name + " , age: " + e.age);
: -
System.out.println("Name: " + emp.get(e).name + " , age: " + emp.get(e).age);