《面试经典系列》- 从底层理解==和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. str2.equals(str3) ? 即地址指向的内容相同吗? true
  6. str2.equals(str3) ? 即地址指向的内容相同吗? true

四、总结

1、基础数据比较

  • 使用“==”是比较值是否相等。
    2、引用数据比较

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值