最近準備再刷刷面試題,將面試題中比較經典和核心的內容寫成系列文章發表在公眾號中,鞏固基礎知識,分享給大家,歡迎大家持續關注【程式新視界】,下面是本系列第1篇,
大多數面試的第一題不是讓說說面向物件,就是關于字符的,本篇文章就從各方面來聊聊“==和equals的區別”,
概念上的區別
針對字串(注意僅限字串)的比較,==和equals的區別有以下兩點:
(1)"=="是判斷兩個變數或實體是不是指向同一個記憶體空間,
(2)"equals"是判斷兩個變數或實體所指向的記憶體空間的值是不是相同,
單純從抽象的概念來看上面的描述還是比較晦澀難懂的,為了講解清楚上面的概念,我們先來簡單了解一下JVM記憶體分配的知識,
創建物件的記憶體分配
在JVM中,記憶體分為堆記憶體和堆疊記憶體,通常情況,當我們通過new關鍵字創建一個物件時,就會呼叫物件的建構式來開辟空間,將物件資料存盤到堆記憶體中,與此同時在堆疊記憶體中生成對應的參考,
String str = new String("程式新視界");
上述代碼中,真實的String物件存盤在堆記憶體中,str變數僅持有指向該物件的參考地址,當在后續代碼呼叫時,用的都是堆疊記憶體中的參考(str指向的地址),
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物件并且兩個String物件的值的char[]陣列中的每個元素值都相等,則它們便是相等的,
看完了上述代碼,大家可能就明白了在講述它們的區別時為什么要添加上“注意僅限字串”的備注了,String的equals方法之所以比較的是值,是因為它重寫了equals方法,
匯總一下,針對String的比較可以用下面一張圖來展示:

我們知道Java中所有的類都繼承自Object物件,而Object物件中也定義了equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
我們看到了什么?Object的equals方法比較的竟然也是參考地址!所以,如果單單的說“==”比較的是參考,equals比較的是參考對應的值,是錯誤的!這里要限定于String類這個范圍,
當我們定義一個類時,如果未重寫equals方法時便使用的是Object默認的equals方法,如果重寫該方法,則按照重寫的方法實作進行比較,String的equals方法便是重寫的示例之一,
特殊的String定義
String除了通過new的形式進行定義,還可以通過等號賦值的形式:
String str = "程式新視界";
這是一種非常特殊的形式,不需要new就可以產生物件,和new有本質的區別,這種形式的賦值在java中叫直接量,它是存在于常量池中,而不是像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
第一行,因為都是通過賦值創建物件,當記憶體中已經存在x對應的物件,賦值y物件時直接將參考指向原有物件,因此相等,
第二行,因為z通過new形式創建,會創建新的物件,此處比較的是兩個物件的參考地址,因此不相等,
第三、四行,均比較字串的實際值,因此相等,
下面再看一下未重寫equals方法的物件比較,對應的物體類定義和單元測驗方法如下:
@Test
public void testObject(){
Person p1 = new Person("Tom");
Person p2 = new Person("Tom");
System.out.println(p1.equals(p2));
}
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;
}
}
執行上述方法,列印結果為false,
通過以上兩個實體,均驗證了我們上面所講的理論,
小結
經過上面的分析,理解了底層的邏輯,想必大家再遇到類似面試題時便能準確回答,
簡單的說通過等號比較的是參考,通過equals比較的是值,從嚴格意義上來說是錯誤的,通過JVM物件的存盤形式以及重寫equals方法等底層實作原理來進行解答才能體現你的實力,而不是死記硬背,
下篇文章,我們來講講new String的形式創建了幾個物件及底層邏輯,歡迎持續關注,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/53061.html
標籤:Java
