java中==和equals和hashCode的区别

首先对这三种操作符分别进行解释说明。

1. ==

==可以操作两种数据,一种是数值类型,一种是引用类型。

  1. 数值类型
    顾名思义,对数值类型使用“==”就是对两个数据的值进行比较,即使这两个数据是不同的类型,只要他们的值相等,“==”的结果就是相等的。
public static void main(String[] args) {
        System.out.println(97 == 'a');     //true
        System.out.println(97 == 97.0000);   //true
    }
  1. 引用类型
    对引用类型的比较,并不是比较其值,而是比较其引用的对象在内存中的地址是否相同。
public static void main(String[] args) {
        String a = new String("aaaaaa");
        String b = new String("aaaaaa");
        System.out.println(a == b);    //false
    }

因为a与b是两个不同的对象,他们在内存中的地址也不相同,所以结果为false。

  1. 小结
  • 对于两个数值类型使用“==”,就是对其值进行比较,即使其类型不同也没有关系。
  • 对于两个引用类型而言,比较的是其引用的对象在内存中的位置,如果位置相同则为true。即这两个引用类型引用的是同一个对象。

2. equals

equals是Object的实例方法,用于比较其content是否相同。
首先对于默认的Object的equals方法而言,其源码为:

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

从中可以看出来,其效果与使用“==”是相同的,即为比较两个对象在内存中的地址是否相同。
然而对于继承Object的类来说,它们重写了equals方法。以String类为例:

public static void main(String[] args) {
        String a = new String("aaaaaa");
        String b = new String("aaaaaa");
        System.out.println(a.equals(b));    //true
    }

如果按照Object类中的equals方法来进行比较的话,应该是true才对,但实际结果为false,这就是因为String重写了equals方法:

public boolean equals(Object anObject) {
        if (this == anObject) {      //对象在内存中地址相同时返回true
            return true;
        }
        if (anObject instanceof String) {        //对象是否为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) {      //对String中的char进行比较
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

从上述源码看出,String的equals实现首先是使用“==”进行比较,如果是同一个对象则返回true,如果不是相同的对象,则判断是否是同一类型,相同的话则对String的值(即组成String的char)进行比较。java中所有内置类的equals方法均是这样实现的,例如Integer等

3. hashCode

hashCode在Object类中的实现是将对象在内存中的地址转化为一个int类型。
然而在实际应用中,Object的子类会对这个方法进行重写,以满足各自的需求,下面还是以String类为例。
我们有一个统计世界上所有人名的需求,将其放入一个set中,而set是不能够有重复数据的,那我们怎么判断新加入的数据是否和set中已有的数据相同呢?可能有人会说使用重写的equals方法,但是假如set中已经有几十万的数据了,那每添加一次数据,就要和之前存在的几十万数据进行equals比较,这就太浪费时间和计算资源了。
这个时候就需要hashCode的帮助了,hashCode能够通过一个特定的算法对每一个对象得到一个特定的值,这个值重复的概率很低。
因此我们对每一个加入到set中的数据都求出其hashCode,然后把这个hashCode作为其在set中的位置。这样基本上每一个不同的数据都能够找到其在set中的位置,而且因为相同的对象使用hashCode方法得到的值是一样的,这就保证set中不会存在相同的数据了。
hashCode的源码如下所示:

/**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
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;
    }

从中可以看出,该值是使用s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1]这个算法得到的,而这个算法所需要的数据,如val[i], value.length等均是equals方法实现中所需要的数据,可以这样说hashCode方法就是使用equals方法中的数据进行特定的算法运算后得到的值
这样一来,hashCode与equals方法的关系就很明显了,在添加数据到set这种拥有不重复数据的集合中时,使用equals方法需要进行大量的计算,而hashCode就是帮助处理这种情况的。因为其内部实现使用了相同的数据,只是算法不同,所以:

  1. equals方法返回“true”,其hashCode方法返回的值也是相同的。
  2. equals方法返回“false”,其hashCode方法返回的值不一定不同,因为其内部实现的算法不能够保证输入值不同,输出值也不同。例如1 + 1 = 2 , 0 + 2 = 2。
  3. hashCode返回的值不同,其equals方法返回的一定是“false”

4. 总结

  • hashcode是系统用来快速检索对象而使用
  • equals方法本意是用来判断引用的对象是否一致
  • 重写equals方法和hashcode方法时,equals方法中用到的成员变量也必定会在hashcode方法中用到,只不过前者作为比较项,后者作为生成摘要的信息项,本质上所用到的数据是一样的,从而保证二者的一致性。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容