资讯专栏INFORMATION COLUMN

“==”、“equals()”、“hashcode()”之间的秘密

Richard_Gao / 3401人阅读

摘要:它也是用来判断两个对象是否相等,所以也得分不同的情况来说明。什么是的作用是获取哈希码,也称为散列码它返回的一个整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。它定义在的中,这就意味着中的任何类都包含有函数。

前言

万丈高楼平地起,今天的聊点基础而又经常让人忽视的话题,比如“==”与“equals()”区别?为何当我们重写完"equals()"后也要有必要去重写"hashcode()"呢? ... 带着这些问题,我们一起来探究一下。

概念

"==":它主要是判断符号两边的“对象”的值是否相等,而这里的“值“”又有所区分了。

基础数据类型:比较的就是自身的值,这个跟我们常规的理解是基本一致的。

引用数据类型:比较的对象的内存地址。

“equals()”:它也是用来判断两个对象是否相等,所以也得分不同的情况来说明。

在当前类中,没有重写equals方法的话,默认的实现跟"=="的实现是一样的。下面是Object类的equals方法实现。

在当前类中,重写了equals方法,此时判断的依据就是你重写的逻辑。

怎样重写equals()方法?

1、自反性:对于任何非空引用x,x.equals(x)应该返回true。

2、对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。

3、传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。

4、一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。

5、非空性:对于任意非空引用x,x.equals(null)应该返回false。

由此可以看出,重写一个equals()方法,需要注意的点还是比较多的,这里给出一个参考的事例。

public class EqualsDemo {
    private String name;
    private String info;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EqualsDemo that = (EqualsDemo) o;

        if (name != null ? !name.equals(that.name) : that.name != null) return false;
        return info != null ? info.equals(that.info) : that.info == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (info != null ? info.hashCode() : 0);
        return result;
    }
}

有些读者可能会感到奇怪,不是说重写equals()方法吗,为什么这里又出现了一个hashcode()?所以这里又引出了我们的另一个主角hashcode()方法,当我们重写了equals()方法后,它就一定会出现,也会“吵着“自己也要被重写。

什么是hashcode()?

hashCode() 的作用是获取哈希码,也称为散列码;它返回的一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap、HashTable等。它定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。

当我们在上面的集合插入对象的时候,java是怎么知道里面是否有重复的对象呢?可能大家第一反应是equals方法,没错这方法可以实现这个功能,但是当集合里面有成千上万个元素的时候,效率会如何呢?答案当然是比较差了,所以才会出现了哈希码。

public V put(K key, V value) {
    //判断当前数组是否等于{},若是则初始化数组
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        //判断 key 是否等于 null,是则将把当前键值对添加进table[0]中,遍历table[0]链表
        //如果已经有null为key的Entry,则修改值,返回旧值,若无则直接添加。
        if (key == null)
            return putForNullKey(value);
        //key不为null则计算hash
        int hash = hash(key);
        //搜索对应hash所在的table中的索引
        int i = indexFor(hash, table.length);
        for (Entry e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        //修改次数
        modCount++;
        addEntry(hash, key, value, i);
        return null;
}

这里是jdk7中 Hashmap put()方法的实现,通过源码的注释可以看出执行的流程,需要更详细的了解HashMap可以参考我之前发在开源中国的博客《Java7 HashMap全面解读! 》,链接:https://my.oschina.net/199212...

经过概念的介绍,知道为什么重写完equals()后要接着重写hashcode()了吧?

People p1=new People("小明",18);
People p2=new People("小明",18);

此时重写了equals方法,p1.equals(p2)一定返回true,假如只重写equals而不重写hashcode,那么Student类的hashcode方法就是Object默认的hashcode方法,由于默认的hashcode方法是根据对象的内存地址经哈希算法得来的,显然此时s1!=s2,故两者的hashcode不一定相等。所以在一些集合的使用当中会出现问题。

总结

小小的几个方法,没想到却有这么多“坑”,而且在面试中也会经常被问到,在金三银四的时候,但愿各位不会陷在这里。

喜欢的话,关注一下微信公众号《深夜里的程序猿》,每天更新高质量IT文章

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77538.html

相关文章

  • 面试官让你说说==和equals()区别,重写equals必须重写hashcode方法吗

    摘要:如果我们不重写的方法,那么就会默认调用的方法小王小王我们可以看到以上的运行结果违背了的规定如果返回,那么方法必须返回相同的整数所以我们需要对对象的方法进行重写通过重写让其与对象的属性关联起来,那么就能够达到为,那么的值也相等。 面试官让你说说==和equals()的区别,重写equals必须重写hashcode方法吗 本身特质来说 ==:操作符 equals():方法 适用...

    1fe1se 评论0 收藏0
  • 面试官:“你重写过 hashcodeequals 么,为什么重写equals时必须重写hash

    摘要:介绍的作用是获取哈希码,也称为散列码它实际上是返回一个整数。所以具有相索引的对象,在该散列码位置处存在多个对象,我们必须依靠的和本身来进行区分。 1.hashCode介绍 hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个散列码的作用是确定该对象在散列表中的索引位置,如果有看我的上一篇文章 什么是散列表,那么这里的散列码就相当于上文中根据首字母查...

    asce1885 评论0 收藏0
  • Object对象你真理解了吗?

    摘要:无论在中出现什么,都可以认为它是对象除了八大基本数据类型。让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。但是要注意的是方法调用后,被唤醒的线程不会立马获得到锁对象。主要的区别在于在释放同时,释放了对象锁的控制。 前言 五一回家又断更了一个放假时间了~~~ 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!...

    anquan 评论0 收藏0
  • javaequal和==区别(转载)

    摘要:更好的办法把所有的都到缓冲池去吧最好在用到的时候就进行这个操作然后就可以用比较两个字符串的值了二简单数据类型和封装类中的和为每一个简单数据类型提供了一个封装类,每个基本数据类型可以封装成对象类型。 值类型是存储在内存中的堆栈(以后简称栈),而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中。 ==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...

    cncoder 评论0 收藏0
  • java集合-Set

    摘要:集合判断两个元素的标准是两个对象通过方法比较相等,并且两个对象的方法返回值也相等。的集合元素也是有序的,以枚举值在类内的定义顺序来决定集合元素的顺序。是所有实现类中性能最好的,但它只能保存同一个枚举类的枚举值作为集合元素。 Set集合通常不能记住元素的添加顺序。Set不允许包含重复的元素。 Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作...

    xavier 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<