《面试经典系列》- 从底层理解==和equals的区别
Posted qiuhaitang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《面试经典系列》- 从底层理解==和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个字符串的内存状态应该是下面这样的。
从上图我们可以看出来:
- String str1 = "hello world"; 会在堆区存放一个字符串对象;
- String str2 = new String("hello world"); 会在堆区再次存放一个字符串对象;
- String str3 = str2; 这时候 str3 和 str2 是两个不同的引用,但是指向同一个对象。
借助于上图,我们再次比较:
- str1 == str2 ? 即地址指向的是同一个地方吗? 当然是 false;
- str1 == str3 ? 即地址指向的是同一个地方吗? 当然是 false;
- str2 == str3 ? 即地址指向的是同一个地方吗? 明显内容是一样的,当然是 true;
- str1.equals(str2) ? 即地址指向的内容相同吗? true
- str1.equals(str3) ? 即地址指向的内容相同吗? true
- 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 指向它。
以上是关于《面试经典系列》- 从底层理解==和equals的区别的主要内容,如果未能解决你的问题,请参考以下文章
前端经典面试题 | 吊打面试官系列 之 说说你对TypeScript 和 JavaScript的理解
一道经典的Java面试题:equals ,== 和hashcode()的区别