【Java源码JDK1.8】equals()和==的区别?

本文详细探讨了Java中equals()方法与==运算符的区别,包括它们在不同场景下的行为,如基本类型、封装类型及字符串的比较。同时,文章解释了为何在重写equals()时必须重写hashCode(),并提供了相关源码分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、equals()和==的区别

  1. ==是基本运算符,用来比较对象的引用是否指向同一块内存地址。
  2. equals()是一个方法,不可以对8种基本类型进行比较,见源码1,它默认的方法中也使用了==,比较的也是对象的地址。见源码2,只不过equals()可以对其进行重写,像String、Date、Math、File、包装类等大部分类都重写了Object的equals()方法。重写后的equals(),可以把它理解为比较值是否相等。
  3. 重写equals方法也要重写hashCode,并且遵循五个条件。

源码1. equals是根类Obeject中的方法:

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

源码2. String类源码中重写的equals方法如下:

public boolean equals(Object anObject) {
// 1. 检查是否为同一个对象的引用,如果是直接返回 true;
        if (this == anObject) {
            return true;
        }
/*2.判断anObject是否为String类的实例,如果不是直接返回false,如果是则取值比较大小。
注:instanceof 测试一个对象是否为一个类的实例
 **/
        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;
    }

二、equals()和==的实战

为什么会出现以下现象?

        //1. 比较基本类型
        int m=1;
        int n=1;
        // System.out.println(m.equals(n)); // 报错
        System.out.println(m == n);  // true
        //System.out.println(m.hashCode());  // 报错
        //System.out.println(n.hashcode());  // 报错

        //2. 比较new出来的封装类型
        Integer x = new Integer(1);
        Integer y = new Integer(1);
        System.out.println(x.equals(y)); // true
        System.out.println(x == y);      // false

        //3. 比较非new封装类型 [-128, 127] 
        Integer x1 = 127;
        Integer y1 = 127;
        System.out.println(x1.equals(y1)); // true
        System.out.println(x1 == y1);      // true

        //4. 比较非new封装类型非[-128, 127] 
        Integer x2 = 128;
        Integer y2 = 128;
        System.out.println(x2.equals(y2)); // true
        System.out.println(x2 == y2);      // false
        
       //5. 比较字符串
        String s1="abc";
        String s2="abc";
        System.out.println(s1==s2);  // true
        System.out.println(s1.equals(s2));  // true

        //6. 比较非new字符串常亮
        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1.equals(str2)); //true
        System.out.println(str1==str2); //false

1. 比较基本类型
对于基本数据类型(byte,short,char,int,float,double,long,boolean)来说,他们是作为常量在方法区中的常量池里面以HashSet策略(HashSet中不允许有重复的元素)存储起来的。因此在常量池,一个常量只会对应一个地址。所以不管是再多的 1,其内存地址都为同一个。
2. 比较new出来的封装类型
new String(“hello”)会在堆内存中创建一个实例,开辟新的内存空间,故==为falsie。但是源码2中,String类源码中重写了equals方法,对单个值的进行比较。
3. 比较非new封装类型 [-128, 127]
4. 比较非new封装类型非[-128, 127]
对于两个非 new 生成的 Integer 对象进行比较时,如果两个变量的值在区间 [-128, 127] 之间,则比较结果为 true,否则为 false。Java 在编译 Integer i = 100 时,会编译成 Integer i = Integer.valueOf(100),而 Integer 类型的 valueOf 的源码如下所示:

public static Integer valueOf(int var0) {    
       return var0 >= -128 && var0 <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[var0 + 128] : new Integer(var0);
}

从上面的代码中可以看出:Java 对于 [-128, 127] 之间的数会进行缓存,比如:Integer i = 127,会将 127 进行缓存,下次再写 Integer j = 127 的时候,就会直接从缓存中取出,而对于这个区间之外的数就需要 new 了。
5. 比较字符串
在Java执行时会维护一个String池(pool),对于一些可以共享的字符串对象,会先在String池中查找是否存在相同的String内容(字符相同),如果有就直接返回,不创建新对象。
6. 比较非new字符串常量
new String(“hello”)会在堆内存中创建一个实例,开辟新的内存空间,故==为falsie。但是,String类源码中重写了equals方法,对单个值的进行比较。

三、为什么重写equals一定要重写hashcode?: link1link2

要求:对两个对象,如果equals方法返回true,则hashcode必须也一样!
但是:默认的hashcode方法是根据对象的内存地址经哈希算法得来的,故equals()为true时,两者的hashcode不一定相等。
所以:重写equals一定要重写hashcode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值