• 《面试经典系列》- 从底层理解==和equals的区别


    前言

      在我们Java面试中,基础知识基本上比定会考核的点,而“==和equals的区别”则是面试官最喜欢、最经常问的问题。

      但我们看了不少的文章、解释,总是一头雾水、一知半解的,往往很容忘记。今天,我带大家从底层去深入理解这两个玩意的区别,相信下次面试官再问的时候,肯定能镇住面试官

    一、初始“==”的含义

      在Java中,“==”的作用主要有两个:

      1、基础数据类型:比较的是两者的值是否相等,比如两个 int 类型的变量,比较的是变量的值是否相等。

      2、引用数据类型:比较的是引用地址是否相同,比如新建了两个 User 对象,比较的是两个 User 的地址是否一样。

      到这里,有些人就有会疑问了:你这里怎么用了个User对象,怎么不是String?别急,请允许我卖个关子。

    二、理解equals的含义

      我们通过Object的源码,先看看Object里面的equals方法

       通过源码,我们可以看到equals方法比较的是当前对象的引用和 obj 的引用是否相同,也就是说默认比较的就是地址

      我们刚才使用的是 User 对象而不是String,在这里“==”比较的就是引用地址,“equals”也是比较引用地址,这两者是没有区别的。

    public class MobileTestBase {
    
        public static void main(String[] args) {
    
            int a = 2;
            int b = 2;
            //常量比较的是两者的值,故为 ture;
            System.out.println(a==b);
    
            User user1 = new User();
            User user2 = new User();
            //普通对象User,"=="和"equals"作用是一样,比较两者的引用地址,均为 false
            System.out.println(user1==user2);
            System.out.println(user1.equals(user2));
        }
    }

       到这里,我们发现,好像“==”和“equals”并没有什么区别,但是,接下来的String类型,就有点意思了,且听我徐徐道来。

    三、重写equals

      1、String中的equals方法

      看到标题,相信我们已经有点印象了,Object对象里面的“==” 和 “equals” 没有什么区别,这样的 equals 方法是没有什么意义的。

      但是,我们可以看到 String 在 Object 的基础上对 equals 进行重写,那么 equals 的逻辑、功能自然就发生变化了。至于怎么重写,我们一起到 String 源码中寻找答案吧。

       从源码中可以看出:String 中的 equals 方法是在比较字符串的内容是否一样。也就是说,如果像 String、Date 这些重写 equals 的类,在使用的时候会和 Object 的 equals 不一样。

      2、测试String

      看看下面的测试代码:

    public class Test {
    
        public static void main(String[] args) {
    
            String str1 = "hello world";
            String str2 = new String("hello world");
            String str3 = str2;     //赋值,引用传递;
    
            System.out.println(str1 == str2);           // false
            System.out.println(str1 == str3);           // false
            System.out.println(str2 == str3);           // true
    
            System.out.println(str1.equals(str2));      // true
            System.out.println(str1.equals(str3));      // true
            System.out.println(str2.equals(str3));      // true
        }
    }
    

      可以看到,定义了3个字符串,分别使用“==” 和 “equals” 比较,出现了不同的结果。其中的原因,就需要我们从内存的角度去解释了。

      3、内存解释

      在Java中,我们一般把对象存放在堆区,把对象的引用存放在栈区。因此,上面3个字符串的内存状态应该是下面这样的。

       从上图我们可以看出来:

    1. String str1 = "hello world"; 会在堆区存放一个字符串对象;
    2. String str2 = new String("hello world"); 会在堆区再次存放一个字符串对象;
    3. String str3 = str2; 这时候 str3 和 str2 是两个不同的引用,但是指向同一个对象。

      借助于上图,我们再次比较:

    1. str1 == str2 ? 即地址指向的是同一个地方吗? 当然是 false
    2. str1 == str3 ? 即地址指向的是同一个地方吗? 当然是 false
    3. str2 == str3 ? 即地址指向的是同一个地方吗? 明显内容是一样的,当然是 true
    4. str1.equals(str2) ? 即地址指向的内容相同吗? true
    5. str1.equals(str3) ? 即地址指向的内容相同吗? true
    6. str2.equals(str3) ? 即地址指向的内容相同吗? true

      到了这里,不知道我们是否能理解?

     四、总结

      1、基础数据比较

        使用“==”是比较值是否相等

      2、引用数据比较

    • 重写了equals方法,比如String类。
      • “==”    :比较的是String的引用是否指向同一块内存
      • “equals”:比较的是String的引用的对象内容是否相等;  
    • 没有重写equals方法,如User等自定义类。
      • “==” 和 “equals” 比较的都是引用是否指向了同一块内存

     五、其他

      String 类型还没结束,有一个小知识点需要注意下,如下:

    public class Test {
    
        public static void main(String[] args) {
    String str1 = "hello world"; String str2 = new String("hello world"); str2 = str2.intern(); System.out.println(str1 == str2); //true System.out.println(str1.equals(str2)); //true } }

      细心就会发现,中间多了个 intern 方法。这个方法表示,检查字符串池中是否存在,如果存在,那就直接返回 true。因为这里 str1 首先会在字符串池里面有一个,然后 str2.intern() 发现池子里有了,就不再新建了,直接把 str2 指向它。

  • 相关阅读:
    LeetCode 21. 合并两个有序链表
    LeetCode 20. 有效的括号
    LeetCode 19. 删除链表的倒数第N个节点
    AI
    http
    IP地址
    wiodows /linux CMD
    git
    AI
    JS常用的获取值和设值的方法
  • 原文地址:https://www.cnblogs.com/qiuhaitang/p/12560515.html
Copyright © 2020-2023  润新知