当我重写 equals() 方法时,为什么要重写 hashCode() ?

发布于 2024-08-30 08:06:33 字数 904 浏览 7 评论 0原文

我从很多地方和来源听说,每当我重写 equals() 方法时,我也需要重写 hashCode() 方法。但请考虑下面的代码,

package test;

public class MyCustomObject {
    
    int intVal1;
    int intVal2;
    
    public MyCustomObject(int val1, int val2){
        intVal1 = val1;
        intVal2 = val2;
    }
    
    public boolean equals(Object obj){
        return (((MyCustomObject)obj).intVal1 == this.intVal1) && 
                (((MyCustomObject)obj).intVal2 == this.intVal2);
    }
    
    public static void main(String a[]){
        MyCustomObject m1 = new MyCustomObject(3,5);
        MyCustomObject m2 = new MyCustomObject(3,5);
        MyCustomObject m3 = new MyCustomObject(4,5);
        
        System.out.println(m1.equals(m2));
        System.out.println(m1.equals(m3));
    }
}

这里的输出为真,为假,完全符合我想要的方式,而且我根本不关心覆盖 hashCode() 方法。这意味着 hashCode() 覆盖是一种选项,而不是像大家所说的那样是强制性的。

I have heard from many places and sources that whenever I override the equals() method, I need to override the hashCode() method as well. But consider the following piece of code

package test;

public class MyCustomObject {
    
    int intVal1;
    int intVal2;
    
    public MyCustomObject(int val1, int val2){
        intVal1 = val1;
        intVal2 = val2;
    }
    
    public boolean equals(Object obj){
        return (((MyCustomObject)obj).intVal1 == this.intVal1) && 
                (((MyCustomObject)obj).intVal2 == this.intVal2);
    }
    
    public static void main(String a[]){
        MyCustomObject m1 = new MyCustomObject(3,5);
        MyCustomObject m2 = new MyCustomObject(3,5);
        MyCustomObject m3 = new MyCustomObject(4,5);
        
        System.out.println(m1.equals(m2));
        System.out.println(m1.equals(m3));
    }
}

Here the output is true, false exactly the way I want it to be and I dont care of overriding the hashCode() method at all. This means that hashCode() overriding is an option rather being a mandatory one as everyone says.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

执手闯天涯 2024-09-06 08:06:33

它适合您,因为您的代码不使用任何需要 hashCode() API 的功能(HashMap、HashTable)。

但是,您不知道您的类(可能不是一次性编写的)稍后是否会在确实使用其对象作为哈希键的代码中被调用,在这种情况下,事情将会受到影响。

根据文档对象类

hashCode的通用约定是:

  • 每当在 Java 应用程序执行期间对同一对象多次调用 hashCode 方法时,只要对象上的 equals 比较中使用的信息没有被修改,hashCode 方法就必须始终返回相同的整数。从一个应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。

  • 如果两个对象根据 equals(Object) 方法相等,则对这两个对象调用 hashCode 方法必须产生相同的整数结果

It works for you because your code does not use any functionality (HashMap, HashTable) which needs the hashCode() API.

However, you don't know whether your class (presumably not written as a one-off) will be later called in a code that does indeed use its objects as hash key, in which case things will be affected.

As per the documentation for Object class:

The general contract of hashCode is:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

尘世孤行 2024-09-06 08:06:33

因为HashMap/Hashtable会先通过hashCode()来查找对象。

如果它们不相同,hashmap 将断言对象不相同并返回映射中不存在。

Because HashMap/Hashtable will lookup object by hashCode() first.

If they are not the same, hashmap will assert object are not the same and return not exists in the map.

焚却相思 2024-09-06 08:06:33

您需要 @Override 两者都不需要,是因为它们与 API 其余部分相互关联的方式。

您会发现,如果将 m1 放入 HashSet 中,则它不会 contains(m2)。这是不一致的行为,可能会导致很多错误和混乱。

Java 库具有大量功能。为了让它们为您工作,您需要遵守规则,并确保 equalshashCode 一致是其中之一最重要的。

The reason why you need to @Override neither or both, is because of the way they interrelate with the rest of the API.

You'll find that if you put m1 into a HashSet<MyCustomObject>, then it doesn't contains(m2). This is inconsistent behavior and can cause a lot of bugs and chaos.

The Java library has tons of functionalities. In order to make them work for you, you need to play by the rules, and making sure that equals and hashCode are consistent is one of the most important ones.

南街女流氓 2024-09-06 08:06:33

大多数其他评论已经给了你答案:你需要这样做,因为有集合(即:HashSet、HashMap)使用 hashCode 作为“索引”对象实例的优化,这些优化期望如果: a.equals(b) ==>; a.hashCode() == b.hashCode() (注意,逆矩阵不成立)。

但作为附加信息,您可以做这个练习:

class Box {
     private String value;
     /* some boring setters and getters for value */
     public int hashCode() { return value.hashCode(); }
     public boolean equals(Object obj) { 
           if (obj != null && getClass().equals(obj.getClass()) { 
               return ((Box) obj).value.equals(value); 
            } else { return false; }
     }
}

这样做:

Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false

您从这个示例中学到的是使用可以更改(可变)的属性实现 equalshashCode这是一个非常糟糕的主意。

Most of the other comments already gave you the answer: you need to do it because there are collections (ie: HashSet, HashMap) that uses hashCode as an optimization to "index" object instances, an those optimizations expects that if: a.equals(b) ==> a.hashCode() == b.hashCode() (NOTE that the inverse doesn't hold).

But as an additional information you can do this exercise:

class Box {
     private String value;
     /* some boring setters and getters for value */
     public int hashCode() { return value.hashCode(); }
     public boolean equals(Object obj) { 
           if (obj != null && getClass().equals(obj.getClass()) { 
               return ((Box) obj).value.equals(value); 
            } else { return false; }
     }
}

The do this:

Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false

What you learn from this example is that implementing equals or hashCode with properties that can be changed (mutable) is a really bad idea.

猫瑾少女 2024-09-06 08:06:33

当使用集合(即 HashMap、HashSet 等)中的 hashCode() 值搜索对象时,这一点尤为重要。每个对象都会返回不同的 hashCode() 值,因此您必须重写此方法,以根据对象的状态一致地生成 hashCode 值,以帮助 Collections 算法在哈希表上定位值。

It is primarily important when searching for an object using its hashCode() value in a collection (i.e. HashMap, HashSet, etc.). Each object returns a different hashCode() value therefore you must override this method to consistently generate a hashCode value based on the state of the object to help the Collections algorithm locate values on the hash table.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文