說一下==和equals的區別,面試官:你確定回答的正確嗎?

程序猿的內心獨白 發佈 2020-08-27T01:22:53+00:00

前言前幾天有個同學非常傷心的來找我,緣由是因為他去面試java工程師在技術方面被刷下來了,他說:面試官問的問題都非常簡單,我都回答上來了,而全感覺回答的還都挺不錯!我就好奇問他:都問什麼了什麼問題,你怎麼回答的?和他交流了5分鐘後,我覺得面試官把他刷下來是對的!!!

前言

前幾天有個同學非常傷心的來找我,緣由是因為他去面試java工程師在技術方面被刷下來了,他說:面試官問的問題都非常簡單,我都回答上來了,而全感覺回答的還都挺不錯!

我就好奇問他:都問什麼了什麼問題,你怎麼回答的?

和他交流了5分鐘後,我覺得面試官把他刷下來是對的!!!


沒錯,這位同學面試的問題是都很簡單,也是面試中常問的知識點,我們今天就拿出一個典型的面試題來分析:String類型下==和equals的區別

==和equals的概念區別

  • "=="是判斷兩個變量或實例是不是指向同一個內存空間。
  • "equals"是判斷兩個變量或實例所指向的內存空間的值是不是相同。

單從概念上來看有點抽象,為了大家能夠更好的理解,我們先來簡單介紹一下JVM在創建對象時的內存分配。


創建對象的內存分配

對JVM有所了解的都知道,JVM內存分為堆內存和棧內存。

棧(stack)內存是由編譯器自動分配和釋放的一塊內存區域,主要用於存放一些基本類型(如int、float等)的變量、指令代碼、常量及對象句柄(也就是對象的引用地址)。

堆(heap)內存是一個程序運行動態分配的內存區域,在Java中,構建對象時所需要的內存從堆中分配。

通常情況,當我們通過new關鍵字創建一個對象時,就會調用對象的構造函數來開闢空間,將對象數據存儲到堆內存中,與此同時在棧內存中生成對應的引用。

例如下面代碼中的String對象就是存儲在堆內存中:

String str = new String("關注 程序猿的內獨白");

String實現equals源碼

為了能讓我們更好的理解,下面我們看一下String實現equals源碼

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

從上面代碼中可以看到,在代碼剛開始的位置使用了==,這代碼如果兩個對象的引用地址地址是相同的,那麼默認對象的值也是相等的。

後面判斷如果傳入的是String 對象,那麼就對String對象中的每個char進行元素比較,如果全相等,那兩個對象就相等。

為什麼String的equals方法之所以比較的是值?大家有沒有明白了?

因此,String中equals的比較可以用下圖來演示:

特殊的String定義

String除了通過new的形式進行定義,還可以通過等號賦值的形式:

String str = "關注 程序猿的內獨白";

這是一種非常特殊的形式,不需要new就可以產生對象,和new有本質的區別。

這種形式的賦值存在於常量池中,而不是像new一樣存放在堆中。

當聲明這樣一個字符串時,JVM會在常量池中先查找有沒有對應值的對象。

如果有,把它賦給當前引用,即原來的引用和現在的引用指向了同一對象。

如果沒有,則在常量池中新創建一個對象,以這形式聲明的字符串,只要值相等,任何多個引用都指向同一對象,而new形式創建String對象是每次調用就產生一個新的對象。



實例驗證

下面以具體的實例來驗證以上結論(很可能是面試題的考點內容哦)

String x = "關注 程序猿的內獨白";
String y = "關注 程序猿的內獨白";
String z = new String("關注 程序猿的內獨白");

System.out.println(x == y); // true
System.out.println(x == z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true


下面再看一下重寫equals方法的對象比較,對應代碼如下:

@Test
public void testObject(){
        Person p1 = new Person("Tom");
        Person p2 = new Person("Tom");

        System.out.println(p1.equals(p2));//false
}

class Person{

        public Person(String name){
                this.name = name;
        }
        
        private String name;

        public String getName() {
                return name;
        }

        public void setName(String name) {
                this.name = name;
        }
}

通過以上兩個實例,是不是可以清晰的驗證我們上面所講的理論。



小結

經過上面的分析,理解了底層的邏輯,想必大家以後遇到類似面試題可以遊刃有餘了!

簡單的說通過==比較的是引用,通過equals比較的是值,從嚴格意義上來說是錯誤的。

通過JVM對象的存儲形式以及重寫equals方法等底層實現原理來進行解答才能體現你的實力,而不是死記硬背。


想了解更多精彩內容,快來關注@程序猿的內心獨白

關鍵字: