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

Java 当我重写equals()方法时,为什么要重写hashCode()?,java,equals,hashcode,Java,Equals,Hashcode,好的,我从许多地方和消息来源听说,每当我重写equals()方法时,我也需要重写hashCode()方法。但是请考虑下面的代码 package test; public class MyCustomObject { int intVal1; int intVal2; public MyCustomObject(int val1, int val2){ intVal1 = val1; intVal2 = val2; }

好的,我从许多地方和消息来源听说,每当我重写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));
    }
}
这里的输出是true,false,这正是我想要的,我根本不在乎重写hashCode()方法。这意味着hashCode()重写是一个选项,而不是像大家说的那样是一个强制选项


我需要第二次确认。

因为HashMap/Hashtable将首先通过hashCode()查找对象


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

之所以需要
@Override
或两者都不存在,是因为它们与API的其余部分相互关联

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


Java库有很多功能。为了让它们为您工作,您需要遵守规则,确保
等于
hashCode
是一致的,这是最重要的一点。

它为您工作,因为您的代码不使用任何需要
hashCode()
API的功能(HashMap,HashTable)

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

根据:

hashCode的总合同为:

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

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


大多数其他评论已经给了您答案:您需要这样做,因为有一些集合(即: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
Set s=newhashset();
框b=新框();
b、 setValue(“你好”);
s、 添加(b);
s、 包含(b);//真的
b、 设定值(“其他”);
s、 包含(b);//错误的
s、 迭代器().next()==b//TRUE!!!b在s中,但包含(b)返回false

从本例中您了解到,使用可更改(可变)的属性实现
equals
hashCode
是一个非常糟糕的主意。

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

该值的可能重复项不是该值的重复项;这是C#,这是Java。(问题非常相似,可能完全相同,但仍然如此。)并且可选地,
hashCode
必须尽最大努力避免在同一程序执行期间可能同时出现的多个值上返回相同的整数。我曾经有一个性能错误,我花了很长时间才使用物理相等和默认(结构)哈希函数来跟踪。此使用满足上述条件,但所有结构相同、物理上不同的值都散列到同一个存储桶中。@Pascal-这是正确的。事实上,文档还在继续:*如果根据equals(java.lang.Object)方法,两个对象不相等,那么对这两个对象中的每一个调用hashCode方法都必须产生不同的整数结果,这不是必需的。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。”……只要合理可行,由类对象定义的hashCode方法确实会为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现,但Java编程语言不需要这种实现技术。)