【问题标题】:Java HashMap when duplicate keys are inserted插入重复键时的Java HashMap
【发布时间】:2012-09-30 16:30:49
【问题描述】:

当插入重复键时,我对 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) 对象替换。这似乎正在发生,因为我得到 Replaced Record Name: Terry , age: 60 作为输出。但是,地图包含记录 Name: Terry , age: 60 而不是 Name: Terry , age: 26

编辑:感谢大家的建议。事实证明我犯了一个非常粗心的错误。我没有打印与键关联的值,而是仅打印键。

正如大家所指出的,解决方案是:

  for(Emp e: emp.keySet())
  {
        Emp empVal = emp.get(e);
        System.out.println("Name: " + empVal.name + " , age: " + empVal.age);
  }

【问题讨论】:

    标签: java hashmap


    【解决方案1】:

    您的输出是打印键,而不是值。在您的代码中,键不会改变,但值会改变。

    例如,如果您将输出循环更改为:

    for (Emp emp : emp.values()) {
      System.out.println("Name: " + e.name + " , age: " + e.age);
    }
    

    我怀疑你会看到你所期待的答案。

    但是:一般来说,我建议不要做你在这里做的事情。各种代码都期望如果a.equals(b) 那么ab 根本没有任何有意义的差异,并且您的Emp 类的equals 实现不符合该合同。例如,如果您使用HashSet 而不是HashMap,您会得到更多奇特的行为并且无法修复它。

    实现这一点的更好方法可能是让EmphashCodeequals 方法正确尊重姓名和年龄,并使您的地图成为Map&lt;String, Emp&gt;,其中键是员工姓名和值为Emp 记录。

    【讨论】:

    • jacobm 谢谢你的好收获。我在这件事上头疼了这么久..讨厌粗心的错误:(
    【解决方案2】:

    我稍微修改了您的代码 - 见下文。新值被放入映射中,但由于键是相等的,第二个放入重用现有键。

    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
    

    【讨论】:

      【解决方案3】:

      在下面的语句中,您实际上是在打印键。通过调用keySet(),您会在map 中获得键的Set,然后您遍历这些键并打印它们。您需要获取值从地图中获取这些键并打印它们.. 所以,更改以下语句:-

      System.out.println("Name: " + e.name + " , age: " + e.age);
      

      与:-

      System.out.println("Name: " + emp.get(e).name + " , age: " + emp.get(e).age);
      

      【讨论】:

        猜你喜欢
        • 2021-02-24
        • 2021-10-15
        • 2016-06-05
        • 1970-01-01
        • 2014-12-17
        • 2010-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多