前言
在我們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 指向它。