java对象比较“==”与“equals()”详解

写在前面

本文的书写仅是个人的理解,目的加深对技术点的理解,知识积累,记录足迹;难免存在疏漏与错误的地方,在此欢迎各位能人异士进行指导与纠正;
如果能帮到你,是我的荣幸。

== 与 equals() 是两个实例对象的什么进行比较?

1、== 是拿两个对象的地址进行比较;对于Java中的基本数据类型比较的即是数值是否相等;对于Java中的引用类型比较的是内存地址是否相等。

2、equals()的比较,是指两个引用类型实例对象之间的比较,基本数据类型不存在equals();那么,两个实例对象间的equals()比较的是什么呢?需要从金字塔的顶端Object对象说起,因为Object是所有类的超类;请看Object类的equal()源码:

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

从源码看出,Object的equals()其实等价于 ==
那么jre中自带的类或者其他第三方开发的类在或者我们自己开发的class的对象之间的equals()比较的是什么呢?如果都是比较的内存地址,那么同一对象的两个实例永远不可以相等,即便他们指向的相同的数据。
显然在我们认知中不是这样的,大家都知道String的equals()是比较两个实例对象的值是否相等,那么它是怎么做到的呢?答案是覆盖equals()方法,下面我们来看下String类的equal()的源码:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

String类的equals方法中,先判断两个对象的地址是否相等,相等就返回true,不相等在判断两个对象的内容是否相等,若相等也可返回true;那么对于String类的equals()来说实际比较的是两个对象的内容是否相等。
从String的equals()源码中也可以得出一个众所周知结论:String类的== 返回true,equals() 一定返回true;equals 返回true,== 不一定返回true。

结论:
equals()判断两个对象是否相等,一般有两种情况:
1.类未覆盖equals()方法,等价于”==“
2.类覆盖了equals()方法,需要看类的具体实现了;一般来说,都是覆盖了equals()来使两个对象的内容相等即返回true(认为这两个对象相等)

equals()的覆盖,必然伴随着hashCode的覆盖,为什么?

hashCode是什么?作用是什么?为什么重写equal方法必须要重新hashCode方法?下面我们来一一解答:

首先,我们抛出一个问题来思考下,大家都知道hashSet中存储的对象是不会存在重复的,那么如何保证不重复呢,是在加入新对象的时候,判断已经存在的对象中是否有和当前待加入的对象相等,相等的话就不会让其加入操作成功。那么问题又回到到相等的问题上,如何判断两个对象是否相等,大家可能会想到使用equals来比较,这确实是个办法,但是如果当前hashSet存储了成千上万的数据,就需要比对成千上万次,效率会是一个问题,那么如何解决呢?答案是hashCode。先来了解下hashCode,咱们在继续探讨这个问题。

hashCode是什么?
hashcode是Object中的函数,所有类都拥有的一个函数,主要返回每个对象的hash值,主要用于哈希表中,如HashMap、HashTable、HashSet。
看下Object的hashCode的源码:

public native int hashCode();

native是调用非Java代码,而是调用的java的开发语言c的代码,这里不做详情解释(因为也不清楚),直接告知结论:通常情况下,不同的对象产生的哈希码是不同的;默认情况下,对象的哈希码是通过将该对象的内部地址转换成一个整数来实现的。
object的hashCode是返回了一个对内存地址做算法处理后的整数。可以把它理解成是和内存地址1对1的关系了,对Object来说,hashCode就是内存地址了。对于其他类,如果没有覆盖了hashCode那么hashCode可以理解就是内存地址,如果覆盖了,就要看实现逻辑了,比如String就覆盖了hashCode方法,逻辑是对内容做算法处理,所以对于String来说,hashCode相等,内容(equals)一般相等(一些特殊情况不相等,比如“Aa”与“BB”的hashCode是相等的因为‘a’与‘B’的Ascii码差了31);内容(equals)相等,hashCode也一定相等。附上String的hashCode()方法源码:

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

说白了,hashCode就是对对象的地址或字符串或数字等继续一定算法处理后返回的数值,程序员根据自己需求定义算法。

了解了hashCode是什么,回到上面的hashSet的问题上,判断当前hashSet中是否已经存在待加入的对象,在数据量太大的时候进行equals显然不合适,那么hashset使用新的方式来处理,即:先判断hashCode是否相等,如果相等在进行equals比较,以此来减少equals的次数从而提升性能
为什么这样就能提升性能了呢,举个例子:
假设有个图书馆,只能往里面存不同 的书籍,重复的不能存;一天,管理员拿到一本《程序员的成长之路》准备往图书馆存,那需要判断现在图书馆中是否已经有这本书了,如果一本本翻一遍,管理员估计要崩溃;聪明的管理员想了个办法,把书籍进行分类,类别可以理解就是hashCode;管理员通过咨询相关人士(算法处理)得知《程序员的成长之路》属于哲学类(hashCode为哲学);到图书馆看看有没有哲学这类的分类,没有就设个书架定义为哲学类,并把书放置在上面;如果已经有了,只需要核对哲学类书架已有的书籍中是否已经存在《程序员的成长之路》就行了,工作量大大降低。

hashCode作用是什么?
所以hashcode()作用就是提高效率。
已知散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。

为什么重写equals必须要同步重写hashCode呢?
hashcode只有在创建某个类的散列表的时候才有用,需要根据hashcode值确认对象在散列表中的位置,但在其他情况下没用。
java中本质上是散列表的类常见的有HashMap,HashSet,HashTable
所以,如果一个对象一定不会在散列表中使用,那么是没有必要复写hashCode方法的。但一般情况下我们还是会复写hashCode方法,因为谁能保证这个对象不会出现再hashMap等中呢?

hashCode与equals重写原则:

java官方提示:我们的hashCode()方法应该时刻和equals()方法保持一致性。
这里的一致性:指的就是我们相同的对象具有相同的哈希码值,具体的总结如下:
1.在程序运行时,同一对象实例多次调用hashCode()方法,应该返回相同的值
2.当两个对象实例的equals()方法比较返回true时,则两个对象的hashCode()方法的返回值也相等
3.对象中作equals()方法比较的Field(字段,属性),都应该用来计算hashCode()的返回值

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值