equals和 == 的区别解析 + hashCode方法的小见解

equals和 == 的区别解析 + hashCode方法的小见解


==既可以比较基本类型(比较值),也可以比较引用类型(比较引用地址)。

来看看两段equals源码
Object类下的equals方法

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

String类下的equals函数

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

可以看出如果是Object下的equals方法,如果没有对其进行重写,那么该方法和==的作用是一样的。

String下的equals方法是重写了的,先比较当前对象的地址和要比较的对象的地址是否相等,如果不相等再判断是否为String的实例化对象,然后比较length和value是否相同。

String的equals方法用的比较广泛,故很多人都误以为所有equals都是比较值的方法。

下面来看一个栗子

public static void main(String[] args) {
        String s1 = "foo";
        String s2 = "foo";
        System.out.println("s1 equals s2 :" + s1.equals(s2));
        System.out.println("s1 == s2 :" + (s1 == s2));
        System.out.println(s1.hashCode() + " " + s2.hashCode());
        System.out.println("--------------------------------");
        String s3 = new String("ff");
        String s4 = new String("ff");
        System.out.println("s3 equals s4 :" + s3.equals(s4));
        System.out.println("s3 == s4 :" + (s3 == s4));
        System.out.println(s3.hashCode() + " " + s4.hashCode());
        System.out.println("--------------------------------");
        StringBuffer sb1 = new StringBuffer("off");
        StringBuffer sb2 = new StringBuffer("off");
        System.out.println("sb1 equals sb2 :" + sb1.equals(sb2));
        System.out.println("sb1 == sb2 :" + (sb1 == sb2));
        System.out.println(sb1.hashCode() + " " + sb2.hashCode());
}

运行结果

s1 equals s2 :true
s1 == s2 :true
101574 101574
--------------------------------
s3 equals s4 :true
s3 == s4 :false
3264 3264
--------------------------------
sb1 equals sb2 :false
sb1 == sb2 :false
460141958 1163157884

原因分析

s1 s2 都是直接赋值的,首先s1会在java常量池中寻找foo对象,如果没有,在堆内存中new一个值为“foo”的对象放在常量池中并返回引用,之后s2再用直接赋值的方法时,如果值相同就直接引用这个对象,不用新建。
另外,因为s1和s2都是String类型的,所以equals方法是重写了的。
s1 == s2 比较的是内存地址,因为s1和s2是同一个对象,故内存地址相同。s1.equals(s2) 为true是因为equals方法重写过,先比较字符串的长度,再比较value,故为true。

s3 s4 都是new新建的,新建对象是直接在堆内存中新建一个对象再对其进行赋值。也就是说用new创建的对象都不是同一个对象。
解释和①大致一样,因为不是相同对象,所以s3 == s4 为false,内存地址不同。

sb1 sb2 是StringBuffer类型(equals没有重写,使用的是Object的)
sb1 == sb2 内存地址不同,为false
sb1.equals(sb2) 由于equals方法没有重写,所以等价于 == ,故也为false。
关于hashCode()方法
以前我一直以为hashCode()可以判断二者是不是同一对象,后来才发现原来不同对象的hashCode也是可以相同的,我们一起来瞅瞅hashCode的源码

* As much as is reasonably practical, the hashCode method defined by
     * class {@code Object} does return distinct integers for distinct
     * objects. (This is typically implemented by converting the internal
     * address of the object into an integer, but this implementation
     * technique is not required by the
     * Java™ programming language.)
     *
     * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
     */
public native int hashCode();

我们可以看到hashCode是一个native方法,看不到实现,注解中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;
}

可以看出对于String类型,hashCode是根据value值决定的,只要value值相同,hashCode就相同。

而StringBuffer没有重写hashCode函数,这意味着该对象的每个实例都应该是唯一的hashCode。

这就解释了为什么s3、s4的hashcode相同以及sb1和sb2的hashcode不同。


Java小白的第一篇文章~
如有什么错误,欢迎指正嗷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值