Java 中什么时候需要重写hashCode()和equals()方法

在自定义类对象做为HashMap的key和HashSet的元素的时候,需要重写该类的hashCode()和equals()方法。

原因如下:

1. 重写equals方法很容易理解。在HashMap中,如果两个对象相等,那他们做为key值,通过调用HashMap的put()方法时,是会更新对应的value值的,是不会再增加一个新的key-value 键值对的。如果不重写equals()方法,默认的equals方法如果是继承自Object类,那定义如下:

    public boolean equals(Object obj) {
        return (this == obj);
    }

也就是只有地址相同,才相等。这肯定不符合我们的要求。所以要重写equals()方法。 

2. 至于重写hashCode()方法,同样以 HashMap的put()方法为例,会先调用hashCode()生成一个散列值,然后对HashMap内部数组长度取余数,做为决定新元素存放的数组位置的下标。当然存在多个对象余数相等的情况,这时候,对应数组的位置就是一个链表(新版本java中,当链表长度超过一定限制时,采用红黑树)。如果两个自定义类的对象被认为是相等的,如果他们的hashCode()不相等,那就会导致在put()第二个对象时,会把第二个对象加进去了,而不是更新第一个对象的value值。

换句话说,在put()时,会先调用hashCode()定位到数组下标(这也是为什么hash table比普通数组快的原因),然后再通过equals()方法挨个比较该数组位置对应的链表上的每个元素,如果有相等的,更新value值。如果没有相等的,则将新的key-value加进去。如果不重写hashCode(),会导致本来应该相等的两个对象,结果分别被加到了数组的不同位置去了。

另外,多说一点,Object类的hashCode()是native方法, equals()方法比较的是对象内存中地址。如果两个对象引用变量值相等(对象堆中地址),说明这两个对象引用指向同一个对象,所以hashCode()返回结果也必然相同。如果两个对象的hashCode()返回结果相同,是不是也一定是这两个引用指向同一个对象呢?

根据JDK的文档:

     * <li>If two objects are equal according to the {@code equals(Object)}
     *     method, then calling the {@code hashCode} method on each of
     *     the two objects must produce the same integer result.
     * <li>It is <em>not</em> required that if two objects are unequal
     *     according to the {@link java.lang.Object#equals(java.lang.Object)}
     *     method, then calling the {@code hashCode} method on each of the
     *     two objects must produce distinct integer results.  However, the
     *     programmer should be aware that producing distinct integer results
     *     for unequal objects may improve the performance of hash tables.
     * </ul>

 不同对象是可以产生相同hash code的。

另外,object类的native hashCode()方法,也不一定是针对对象地址计算的出的结果。以下是jdk10的文档。不同的jdk版本实现的方式也可能不一样。

"(The hashCode may or may not be implemented as some function of an object's memory address at some point in time.)"

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值