当插入重复键时,我对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)ab根本没有任何有意义的区别,并且您的Emp类的equals实现不符合该约定。例如,如果您使用HashSet而不是HashMap,则会得到更多奇怪的行为,并且没有办法解决。

实施此方法的更好方法可能是让EmphashCodeequals方法正确尊重姓名和年龄,并使地图成为Map<String, Emp>,其中键是员工的姓名,值是Emp记录。

10-04 10:19