当插入重复键时,我对Java HashMap有一个非常基本的疑问。
我的意图是创建4个Emp对象。 2个对象(e1和e2)具有相同的hashCode。因此,在插入e1(在e2之后插入)时,哈希图将意识到具有相同哈希值的对象已经存在(对象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
姓名:特里(Terry),年龄:26岁
姓名:约翰,年龄:21岁
我得到的输出:
替换记录名称:Terry,年龄:60
姓名:年龄:60
姓名:特里(Terry),年龄: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);
}
最佳答案
您的输出正在打印键,而不是值。在您的代码中,键不会更改,但值会更改。
例如,如果将输出循环更改为:
for (Emp emp : emp.values()) {
System.out.println("Name: " + e.name + " , age: " + e.age);
}
我怀疑您会看到期望的答案。
但是:一般来说,我建议您不要在这里做什么。各种代码期望如果
a.equals(b)
则a
和b
根本没有任何有意义的区别,并且您的Emp
类的equals
实现不符合该约定。例如,如果您使用HashSet
而不是HashMap
,则会得到更多奇怪的行为,并且没有办法解决。实施此方法的更好方法可能是让
Emp
的hashCode
和equals
方法正确尊重姓名和年龄,并使地图成为Map<String, Emp>
,其中键是员工的姓名,值是Emp
记录。