《面試經典系列》- 從底層理解==和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 指向它。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM