前言
前幾天有個同學非常傷心的來找我,緣由是因為他去面試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方法等底層實現原理來進行解答才能體現你的實力,而不是死記硬背。
想了解更多精彩內容,快來關注@程序猿的內心獨白