【问题标题】:Why it is necessary to override equals when I am overriding hashcode and getting values from hashmap为什么在我覆盖哈希码并从哈希图中获取值时需要覆盖equals
【发布时间】:2015-08-05 04:43:56
【问题描述】:
public class DemoHashSet {
private String name;
private String dob;
private String gender;

public DemoHashSet(String name, String dob, String gender) {
    super();
    this.name = name;
    this.dob = dob;
    this.gender = gender;
}

public String getName() {
    return name;
}

public String getDob() {
    return dob;
}

public String getGender() {
    return gender;
}

@Override
public String toString() {
    return name+" "+dob+" "+gender;
}

@Override
public boolean equals(Object o) {
    return this.name.equals(((DemoHashSet)o).getName());
}

@Override
public int hashCode() {
    int code = this.name.hashCode() + this.dob.hashCode() + gender.hashCode();
    System.out.println("Hash Code: "+code);
    return code;
}

public static void main(String args[]) throws ParseException {

    Map<DemoHashSet, String> hmap = new HashMap<DemoHashSet, String>();

    DemoHashSet obj1 = new DemoHashSet("key1", "121990", "male");
    DemoHashSet obj2 = new DemoHashSet("key2", "122990", "male");
    DemoHashSet obj3 = new DemoHashSet("key3", "123990", "male");
    DemoHashSet obj4 = new DemoHashSet("key4", "124990", "male");
    DemoHashSet obj5 = new DemoHashSet("key5", "125990", "male");

    hmap.put(obj1, "value1");
    hmap.put(obj2, "value2");
    hmap.put(obj3, "value3");
    hmap.put(obj4, "value4");
    hmap.put(obj5, "value5");

    System.out.println("Get values: ");
    System.out.println(hmap.get(new DemoHashSet("key1", "121990", "male")));
    System.out.println(hmap.get(new DemoHashSet("key2", "122990", "male")));
}
}

在这段代码中,我重写了 hashcode() 和 equals() 函数

当我运行此代码时,我得到以下输出:

Hash Code: 1457153183
Hash Code: 1457182975
Hash Code: 1457212767
Hash Code: 1457242559
Hash Code: 1457272351
Get values: 
Hash Code: 1457153183
value1
Hash Code: 1457182975
value2

当我只覆盖 hashCode() 函数和注释 equlas() 方法时,我得到以下输出:

Hash Code: 1457153183
Hash Code: 1457182975
Hash Code: 1457212767
Hash Code: 1457242559
Hash Code: 1457272351
Get values: 
Hash Code: 1457153183
null
Hash Code: 1457182975
null

需要对此行为进行解释,因为在两种情况下计算的哈希码相同,但在第二种情况下会给出 null

【问题讨论】:

标签: java hashmap equals hashcode


【解决方案1】:

需要对此行为进行解释
这是我应该期望的确切预期行为。为什么?
关于 hascode 有一件事,那就是你不能 100% 保证唯一对象的唯一性。这意味着在某些情况下 不同的对象可以有相似的hascode。

HashMap 的实现牢记这一点。因此,当您传递密钥时,他们总是比较 hascode 然后检查相等性(参考检查然后是 equals() 方法)。如果没有找到返回null。你可以查看源代码:

if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k))))

这个代码块说:

  • hash(hascode)对于给定的键和输入键需要相同

  • 给定的键和输入键需要是相同的对象(相同的引用)它们需要通过equals() 方法相等

在你评论 equals 方法的情况下,使用超类的 equals() 方法的默认实现,我猜它实际上只检查引用相等性。所以

DemoHashSet obj1 = new DemoHashSet("key1", "121990", "male");

以后

 new DemoHashSet("key1", "121990", "male") //ins hmap.get()

不引用同一个对象,所以 equals() 返回 false 和 get() 返回 null 作为未找到该键的匹配项。
当您的 equals() 方法根据您的实现存在时,您告诉这些对象是相等的,因为它们具有相同的名称。

哈希码不能保证,也不是平等的。

【讨论】:

    【解决方案2】:

    需要对这种行为进行解释,因为两者都计算了哈希码 场景是相同的,但它在第二种情况下给出 null。

    这一切都与 hashmap 的 get 方法在内部如何工作有关。当您为specified key 调用hashmap 的get 方法时,在内部调用此key's hashcode 方法来计算bucket location。一旦它获得桶位置,它调用指定键的equals方法与该桶内的现有对象(实际上是类Entry对象)进行比较,如果任何对象根据equals方法等于指定对象,则返回该对象。

    案例 1:我正在覆盖 hashcode() 和 equals() 方法

    hmap.get(new DemoHashSet("key1", "121990", "male")) hmap.get(new DemoHashSet("key2", "122990", "male"))

    根据您的 equals 方法实现,如果两个 DemoHashSet 对象具有相同的名称,则它们是相等的。这就是您在这种情况下获得结果的原因。

    案例 2:我只覆盖 hashCode() 函数和注释 equlas() 方法

    hmap.get(new DemoHashSet("key1", "121990", "male")) hmap.get(new DemoHashSet("key2", "122990", "male"))

    在这种情况下,没有可用的自定义 equals 方法实现,因此它将采用默认实现并根据默认实现 - 当且仅当它们的引用相同时,两个对象才是相同的。所以new DemoHashSet("key1", "121990", "male")new DemoHashSet("key1", "121990", "male") 并不相同,即使它们携带相同的值。所以 hashmap 没有在那个桶中获取这些对象。这就是为什么你会得到 null。

    欲了解更多信息:http://javarevisited.blogspot.in/2011/02/how-hashmap-works-in-java.html

    【讨论】:

      【解决方案3】:

      您使用的是HashMap。在内部,HashMap 有许多存储桶,每个存储桶都有您要存储的项目的列表。

      每当您调用 HashMap.get() 时,HashMap 都会调用 DemoHashSet.hashCode() 并使用键参数(可能与模数 (%) 运算符一起使用)来确定要查找的存储桶。

      然后,它将使用DemoHashSet.equals() 方法搜索此列表,以查看它是否可以匹配关键参数。如果equals() 曾经返回true,则返回该值,否则返回null

      来自Object.equals() 的文档:

      注意,一般需要重写hashCode方法 每当此方法被覆盖时,以保持一般 hashCode 方法的契约,它规定相等的对象必须 具有相同的哈希码。

      【讨论】:

        【解决方案4】:

        hadCode() 函数旨在通过将对象的密钥派生到特定的段/桶来将对象存储在特定的段/桶中。要了解此方法的目的,您需要了解 HashTable 或 HashMap 在内部是如何工作的。维基百科是了解它的最佳来源。

        equals() 函数用于检查集合对象中特定对象的存在。

        如果两个对象相等,hasCode 将相同,但 converse 不成立。两个不同的对象可以有相同的hashCode

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-02-17
          • 2019-10-04
          • 2018-08-05
          • 2017-05-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多