【问题标题】:HashMap and HashcodeHashMap 和哈希码
【发布时间】:2014-08-01 02:24:57
【问题描述】:

理想情况下,根据定义,HashMap 不允许重复键;但我无法理解以下逻辑。

我已经定义了一个Employee 类并覆盖了equalshashcode 方法。

public class Employee {

    private String empID;
    public int hashCode() {
        int result = 17;
        result = 37 * result + empID.hashCode();
        return result;
    }
    public boolean equals(Object object) {
        boolean result = false;
        if (object instanceof Employee) {
            Employee employee = (Employee) object;
            result = (this.empID.equalsIgnoreCase(employee.getEmpID()));
        }
        return result;
    }
}
Employee e1 = new Employee("1");
Employee e2 = new Employee("2");

Map<Employee, String> empMap = new HashMap<Employee, String>();
empMap.put(e1, "Emp1");
empMap.put(e2, "Emp2");
Set<Employee> keys = empMap.keySet();
for (Employee e: keys)
{
    e.setEmpID("1");
}
for (Employee e: keys)
{
    System.out.println(e.getEmpID());
    System.out.println(e.hashCode());
}
System.out.println(empMap.get(new Employee("1")) );

我总是得到Emp1 的值。如何获取Emp2的值?

【问题讨论】:

  • 我没有看到任何问题。
  • 您的 equals 会忽略大小写,但您的 hashCode 不会。

标签: java hashmap hashcode


【解决方案1】:

我相信你的钥匙和价值观是倒退的。您应该使用 String 作为键,使用 Employee 类作为值:

Map<String,Employee> empMap = new HashMap<>();
empMap.put("Emp1", e1);
empMap.put("Emp2", e2);

那么您的 Employee 类就不需要 hashCode 和 equals 方法了。您的 Employee 类不适合用作映射键,主要是因为键不应该更改其内部变量。迭代时只看到一个 ID 的原因是:

for (Employee e: keys)
{
    e.setEmpID("1");
}

由于三个原因,它被打破了。 (1) 你不能在映射中修改键的变量,因为映射不会知道它。要更改与值关联的键,您必须 remove() 映射中的该映射,然后 put() 使用新键将其返回。 (2) 如果您同时迭代地图,则无论如何都不允许修改地图(除非您通过地图的迭代器进行)。 (3) 您为所有员工提供相同的密钥,因此地图无法区分他们。

想想你的 Employee 类的目的。如果您真的想将其用作地图key,请删除ID 的setter,因为使用该方法总是错误的。理想的映射键是完全不可变的和最终的。在equals方法中使用equalsIgnoreCase也是错误的,因为那样equals方法和hashCode方法不一致。 (如果 a.equals(b) 为真,则需要 a.hashCode() == b.hashCode(),否则映射将无法正常工作。)当您完成修复 Employee 类以用作映射键时,它只是一个烦人且不必要的包装器围绕String,但是你没有地方放置任何其他员工信息,这就是为什么我建议简单地交换键和值,这样可以一次性解决你所有的问题。

【讨论】:

    【解决方案2】:

    HashMap 无法正常工作,因为您修改了影响equalshashCode 结果的值。你不能那样做。这些方法必须一致。通常,您用于实现相等的任何字段都应为final 以避免此错误。


    另外 - 这不是问题的答案,但您应该阅读 equalshashCode 的合同。您的 Employee 课程违反了他们的合同。

    如果两个对象根据equals(Object) 方法相等,那么对这两个对象中的每一个调用hashCode 方法必须产生相同的整数结果。

    反例:Employee("a")Employee("A")


    推荐阅读:What issues / pitfalls must be considered when overriding equals and hashCode?

    【讨论】:

    • "Employee("a").equals(null) 抛出异常"不,不会。
    • @Boann 哎呀。删除它。
    猜你喜欢
    • 2013-08-28
    • 1970-01-01
    • 2013-06-20
    • 1970-01-01
    • 2012-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多