• Java - equals 与 == 的区别


    概述

    首先理解 == 的概念,== 是 Java 语言中的比较运算符,用于比较两边的值是否相等。当对象使用 == 比较时,比较的是对象的地址是否相等。

    创建一个测试类:

    public class MyData {
        int a = 10;
    }
    
    • 1
    • 2
    • 3

    比较两个对象是否相等:

    @Test
    void test() {
        MyData data1 = new MyData();
        MyData data2= new MyData();
        System.out.println(data1 == data2);			// false
        System.out.println(data1.equals(data2));	// false
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    分析

    在 Java 中,所有的类都默认继承 Object 类,在源码中有介绍:

    在这里插入图片描述
    Object 类的 equals 方法默认使用 == 进行比较,所以如果没有重写 equals 方法的话,默认使用 == 进行比较:

    public boolean equals(Object obj) {
     	return (this == obj);
    }
    
    • 1
    • 2
    • 3

    上面的例子中,我们重写 MyData 类的 equals 方法:

    public class MyData {
        int a = 10;
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj instanceof MyData) {
                MyData myData = (MyData) obj;
                return myData.a == this.a;
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    输出比较结果:

    @Test
    void test() {
        MyData data1 = new MyData();
        MyData data2= new MyData();
        System.out.println(data1 == data2);			// false
        System.out.println(data1.equals(data2));	// true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    == 比较的是对象的地址,而 equals 方法默认使用 == 作为比较运算符,但是可以重写 equals 方法,自定义比较规则。

    总结

    • == 常用于比较原生类型
    • 对象之间比较的是引用地址(对象在栈中的引用地址)是否相等,当引用地址相等时,== 返回 true,而 equals 方法可以返回 true 或者 false 取决于重写方法的实现逻辑。

    拓展

    String 类型的比较

    通过上面的例子,我们知道包装类型使用 == 比较的是引用地址,String 作为一个特殊的包装类型,由于 JVM 提供了常量池,所以需要单独考虑:

    @Test
    void testBaseType() {
        String s1 = "dev";
        String s2 = "dev";
        System.out.println(s1 == s2);	// true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在上面的代码中,由于定义 s1 的时候,会把值给存放到常量池里面;当定义 s2 的时候,会先去常量池里面找 123 这个值是否已经定义过,如果存在会把引用地址赋值给 s2,所以这里 s1 的引用地址等于 s2 的引用地址。

    当使用构造函数创建 String 对象的时候:

    @Test
    void testBaseType() {
        String s1 = "dev";
        String s2 = "dev";
        String s3 = new String("dev");
        System.out.println(s1 == s2);	// true
        System.out.println(s1 == s3);	// false
        System.out.println(s1.equals(s3));	// true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用构造函数创建的 String 对象是直接在堆中创建的,引用地址不一样,所以 == 比较的结果为 false。而 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    可以看出,重写后的 equals 方法比较的是字符串的 ,所以 s1.equals(s3) 结果为 true。

    Integer 与 int 类型的比较

    首先来看一下 Integer 类型的比较:

    @Test
    void testInteger() {
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = new Integer(100);
    
        System.out.println(i1 == i2);	// true
        System.out.println(i1 == i3);	// false
        System.out.println(i1.equals(i3));	// true
    
    	Integer i4 = 128;
        Integer i5 = 128;
        System.out.println(i4 == i5);	// false
        System.out.println(i4.equals(i5));	// true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    为什么会出现这种情况呢?首先,我们要知道:Integer i4 = 128; 这种定义方式会调用 IntegervalueOf() 方法。查看 valueOf 方法的源码:

    public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    
    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
    
        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;
    
            cache = new Integer[(high - low) + 1];
            int j = low;
            // 实例化并缓存起来了
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
    
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
    
        private IntegerCache() {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    可以看到,这里使用了内部类 IntegerCache-128~127(最大值可自定义) 的整数都给提前实例化了,所以无论创建多少个这个范围内的 Integer 对象,都是同一个对象。

    再来看一下 Integer 重写的 equals 方法:

    public boolean equals(Object obj) {
       if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可以看到 Integer 之间的比较,是调用 Integer.ineValue() 获取 int 值然后使用 == 比较的。

    而 int 和 Integer 之间的比较,Integer 类型会自动拆箱成 int 类型,所以可以直接使用 == 进行比较:

    Integer i5 = 128;
    int i6 = 128;
    System.out.println(i5 == i6);	// true
    
    • 1
    • 2
    • 3

    总结

    • 如果 Integer 类型的两个数相等,如果范围在 -128 ~ 127 ,那么用 “==” 返回 true;其余的返回 false。
    • 两个基本类型 int 进行相等比较,直接用 “==” 即可。
    • 一个基本类型 int 和一个包装类型 Integer 比较,用“==” 也可,这个时候,Integer 类型做了拆箱操作。
    • Integer 类型比较大小,要么调用 Integer.intValue() 转为基本类型用 “==” 比较,要么直接用 equals 比较。

    拓展

    Long 和 Short 类型也做了相同的处理,只不过最大值是不可调的。

    参考 Long 源码:

    public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    参考 Short 源码:

    public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    qt6 多媒体开发代码分析(二、录音)
    GUAVA本地缓存01_概述、优缺点、创建方式、回收机制、监听器、统计、异步锁定
    数字图像处理与Python实现-Scikit-Image-图像特征(二)
    苹果酸-壳聚糖纳米孔水凝胶微球/SA/CS/GT三元复合/载血小板源性生长因子壳聚糖水凝胶微球
    【中秋佳节】CSDN卷王们内卷--中秋节要不要休息呢?
    【无标题】LeetCode题解:19. 删除链表的倒数第 N 个结点,JavaScript,详细注释
    漏电继电器 JELR-(120)FG AC220V 零序电流互感器 孔径φ45 上海约瑟
    mysql约束
    电工特种作业操作证登高作业等报名考试费用是怎么样的
    Uniapp中textarea中输入完会触发上一段代码的click事件
  • 原文地址:https://blog.csdn.net/qiaohao0206/article/details/125506543