谈谈javaSE中的和equals的联系与区别

8次阅读

共计 3127 个字符,预计需要花费 8 分钟才能阅读完成。

前言

== 和 equals 是我们面试中经常会碰到的问题。那么它们之间有什么联系和区别呢?今天我们就来聊聊吧!

问题

这里先抛出一些比较典型笔试问题:

int x = 10;
int y = 10;
String str1 = new String("abc");
String str2 = new String("abc");
String str3 = "abc";
String str4 = "abc";
System.out.println(x == y); // 输出?System.out.println(str1 == str2); // 输出?System.out.println(str1.equals(str2)); // 输出?System.out.println(str3 == str4); // 输出?System.out.println(str1 == str3); // 输出?System.out.println(str1.equals(str3)); // 输出?Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);// 输出?System.out.println(f3 == f4);// 输出?

正文

​ 我们通常就是说 ”==” 用来判断两个变量之间的的值是否相等。变量又分为基本数据类型变量和引用类型。如果是基本数据类型的变量直接比较值而引用类型要比较对应的引用的内存的首地址。而 equals 方法 通俗来说就是用来比较两个对象长得是否一样。判断两个对象的某些特征(内容)是否一样。实际上就是调用对象的 equals 方法进行比较。那么我们来看看 equals 方法吧!

​ equals 方法其实是属于 Object 类的方法。因为 Object 类是所有类的直接或间接父类,也就是说所有的类中的 equals()方法都继承自 Object 类,而通过源码我们发现,Object 类中 equals()方法底层实现其实就是是 ”==” 号。

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

那么,在所有没有重写 equals()方法的类中,调用 equals()方法其实和使用 ”==” 号的效果一样,也是比较的对象地址值,然而,Java 提供的所有类中,绝大多数类都重写了 equals()方法,重写后的 equals()方法一般都是比较两个对象的值,比如 String 类,Date 类,基本数据类型的包装类等。可以看哈 String 类的源码:

    public boolean equals(Object var1) {if (this == var1) {return true;} else {if (var1 instanceof String) {String var2 = (String)var1;
                int var3 = this.value.length;
                if (var3 == var2.value.length) {char[] var4 = this.value;
                    char[] var5 = var2.value;
                    for(int var6 = 0; var3-- != 0; ++var6) {if (var4[var6] != var5[var6]) {return false;}
                    }
                    return true;
                }
            }
            return false;
        }
    }

解决

看了上面的描述,相信你可以做对或者回答起大多数这类的问题。但是还需要注意以下两点:

String str3 = "abc";
String str4 = "abc";
System.out.println(str3 == str4); // 输出 true
  • 这里为什么会是 true 呢?按理说 str3 和 str4 是两个对象,”==” 比较的是地址,应该会是 false 才对。如果你是这么想的,那你就不是很了解 String 类。String 类,我们都知道它是不可变的字符序列,存储在常量池中,所以当你声明了一个 str3=”abc” 时,就会在常量池中开辟一个内存空间来存放 ”abc”,下次再声明时,就会在常量池中去找,有,就直接把当前地址赋给变量,没有,就再创建。因此,此处的 str3 和 str4 是指向的同一个内存地址。
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);// 输出 true
System.out.println(f3 == f4);// 输出 false
  • 看到上面的答案是不是感到十分的诧异。其实这里隐藏着一个知识点。就是包装类的缓存问题。下面简单描述一下:

    整型、char 类型所对应的包装类,在自动装箱时,对于 -128~127 之间的值会进行缓存处理。当然其目的就是提高效率。

    缓存处理的原理为:如果数据在 -128~127 这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这 256 个对象存放到一个名为 cache 的数组中。每当自动装箱过程发生时 (或者手动调用 valueOf() 时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过 new 调用包装类的构造方法来创建对象。

    此处以 Integer 类为例,源码参考:

    public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i); // 超过范围就是 new 的 Integer 对象
    }

    这段代码中我们需要解释下面几个问题:

    1. IntegerCache 类为 Integer 类的一个静态内部类,仅供 Integer 类使用,作用就是初始化数组 cache 的,这个过程会在类加载时完成。感兴趣可以去看哈源码,这里就不再粘贴了。2. 一般情况下 IntegerCache.low 为 -128,IntegerCache.high 为 127,IntegerCache.cache 为内部类的一个静态属性。

看到这,相信你对上面抛出的问题,已经可以迎刃而解。答案参考:

        int x = 10;
        int y = 10;
        String str1 = new String("abc");
        String str2 = new String("abc");
        String str3 = "abc";
        String str4 = "abc";
        System.out.println(x == y); // 输出 true
        System.out.println(str1 == str2); // 输出 false
        System.out.println(str1.equals(str2)); // 输出 true
        System.out.println(str3 == str4); // 输出 true
        System.out.println(str1 == str3); // 输出 false
        System.out.println(str1.equals(str3)); // 输出 true

        Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
        System.out.println(f1 == f2);// 输出 true
        System.out.println(f3 == f4);// 输出 false

最后,最近很多小伙伴找我要Linux 学习路线图,于是我根据自己的经验,利用业余时间熬夜肝了一个月,整理了一份电子书。无论你是面试还是自我提升,相信都会对你有帮助!

免费送给大家,只求大家金指给我点个赞!

电子书 | Linux 开发学习路线图

也希望有小伙伴能加入我,把这份电子书做得更完美!

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

推荐阅读:

  • 干货 | 程序员进阶架构师必备资源免费送
  • 神器 | 支持搜索的资源网站
正文完
 0