一次搞定"=="和equals(),含源码解析

来源:互联网 发布:linux启动.sh命令 编辑:程序博客网 时间:2024/04/30 00:22

最近整理了一些常见但容易混淆的问题,也是面试常见题,其中就有”==”和equals()的区别.

坊间有句话叫做:“==”比较的是地址,equals()比较的是值.一般情况下,确实如此.

先说”==”,这个挺容易理解,如果是基本类型,那就是比较两个变量值是否一样;如果是对象,就是比较两个对象在内存中是不是同一个地址,或者说就是比较”==”前后的两个引用是不是指向同一个对象.

再说equals()方法,这个稍微特殊点,因为有些类把equals()重写了,重写之前equals()其实和”==”一个样,重写之后equals()就只比较值的大小.具体看源码就瞬间清楚了:先看类的老祖宗–Object中equals()是咋写的:

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

很明显,Object类中equals()等价于”==”;

再看重写后的equals(),就用String做对比吧,看源码:

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;    }

源码写的很精简,先看第一个if判断,就是个”==”判断,就是说先比较两个对象是否是同一地址,如果地址一样,那这俩就是同一个对象,equals()比较后当然返回true了,也就不需要进行后面判断了(这里其实和Object中一毛一样);
如果第一个if判断返回false,也就是俩对象不是同一个,继续看下面的if判断,instanceof String先判断比较的对象是不是属于String类,如果不是那就不用比了,两个对象物种都不一样还比个毛,直接返回false;
如果equals()比较的对象是String类,继续比较看下个if判断,很明显是比较两个对象长度,长度不一致,就没有比较的必要了,直接false;长度一致,再根据两个String对象的下标,逐个比较是否每个字符相等;

看了String类重写后的equals(),你就会发现所谓的:”==”比较两个对象地址,equals()比较两个对象值的说法,前半句肯定是对的,后半句可以说是”话糙理不糙”,虽然重写后的equals()中也进行过”==”的比较,但那也是为了更快速的比较两个对象的值而服务.顺便补充一点,一般如果重写了equals()的话,也要重写hashCode().那这样做有什么意义呢,看源码,还看String吧:

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时要用31,题外话这里就不多说了.重点是重写后的hashCode(),你会发现,只要两个String对象equals()比较后为true,也就是说如果两个String对象值一样,那么这两个对象的hashcode肯定也是一样的.
反过来说,如果两个对象hashcode相同,这两个对象值却不一定相同.

咦,,为毛不是一个对象配一个专属hashcode,不同对象也可以有同样hashcode吗?当然可以.原因之一就是存储时速度会快上许多.

拿HashMap举例吧,在往集合中put那些key-value时,会先检查有没有已经存在了的key.怎么检查呢?举个栗子:
假设key定义为String,那么在比较时就会优先调用hashCode()比较hash值,如果hashcode不同,key肯定是不存在的,直接插入.如果hashcode相同,再调用equals()比较值,如果equals()返回true,默认两个String对象相同,则更新原来的key-value.
往HashMap存储时,发生hashcode一样的情况,就是所谓的hash碰撞,具体等以后更新HashMap再讲.

原创粉丝点击