Java重写equals方法的同时也要重写hashcode方法

3 篇文章 0 订阅

1.什么是equals方法

源码中的注释:equals方法实现了非空对象的引用之间的等价关系

* The {@code equals} method implements an equivalence relation on non-null object references:

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

因为 == 比较的是两个对象的地址(基本类型比较数值),所以对于没有重写equals方法的对象来说,equals方法就是比较二者的地址是否相等。但我们代码中实际判断两个对象是否相等,是根据自己的需求来对比的(而不是地址)。这时候就需要重写equals方法实现自己的比较逻辑。

 

2.hashcode方法

源码中的注释:返回对象的一个hashcode,这个方法是为了支持哈希表(比如HashMap)的好处

* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.

哈希表:哈希表根据对象的hashcode来计算出对象在哈希表中的存放位置(hashcode的作用)

 

3.分析

HashTable的put方法源码

public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();    
        int index = (hash & 0x7FFFFFFF) % tab.length;    //基于hashcode计算存放位置
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {    
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
}

在HashTable中判断元素是否相等的过程是这样的

if ((entry.hash == hash) && entry.key.equals(key))

这就是重写equals方法同时要重写hashcode方法的原因:

哈希表判断两个对象是否相同是根据两个对象的hash值与equals结果来判断的,我们前面说过,重写equals方法,实现自己的比较逻辑来判断二者是否相等,但是如果不重写hashcode方法,两个对象的hashcode方法返回的就是不一样的值,这样的话,就会导致哈希表认为相等的二者是不相等的,为了防止这样的错误出现,文档规定:重写一个对象的equals方法的时候,也要重写hashcode方法,当两个对象equals返回true时,他们的hashcode也要相同。

* <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.

4.拓展

  • 为什么HashTable中判断两个对象是否相同要同时判断hashcode与equals呢
if ((entry.hash == hash) && entry.key.equals(key))

 原因是性能

当两个对象hash值相同的时候,对象可能相同可能不同

当两个对象hash值不同的时候,对象肯定不同

所以HashTabel在判断对象是否相同时,先判断hash值,hash值不同说明两个对象不相同直接返回,如果hash相同,再进行equals的判断。

这里我个人分析一下性能的对比:

(1) == 运算符

虚拟机中判断两者是否相等的其中一个指令是if_icmpne(所有比较指令都大同小异,差别不过是类型的不同和根据判定结果跳转的地方不同) if_icmpne的执行过程是:先将操作数栈顶的两个元素出栈,进行大小比较,如果相同,入栈1代表boolean为true,不相同入栈0代表boolean为false。这就是 == 操作符的执行流程,非常简单。

(2)equals方法

虚拟机中要执行一个方法,就要先“拼装”一个栈帧(栈帧是方法执行的基本单位,方法的开始到结束的过程,对应着栈帧在虚拟机栈中的入栈和出栈的过程),进行把相关参数传入局部变量表中等操作,然后将栈帧入栈,执行其中的代码,然后栈帧出栈,返回到调用该方法的地方。

可以看出来,执行equals方法,都要入栈出栈,花销要比 == 运算符大很多。而HashTable中可能有非常多的元素,在这样的场景下,每一次比较的性能优化累积下来,性能就能提高很多。

 

  • 前面只说了原因,那么在重写equals方法的时候如何重写hashcode呢

参考文章https://blog.csdn.net/lihui6636/article/details/49470741

 

体会:多看源码和源码中的注释,可以减少很多疑惑。源码中都说明了方法的作用,比在网上查看别人写的资料要靠谱一点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值