解決一個問題的最好方法就是發現一個問題產生的根源,即發現最本質的東西,再去解決它。
Java語言裡面的equals()方法是交給開發者們自己去覆蓋重寫編寫功能的,即讓開發者去定義當滿足什麼條件時,兩個Object是相等的。
equals方法是由Object提供的,允許子類進行重寫。
equals()的原始程式碼實現如下:
public boolean equals(Object obj) {
return (this == obj);
}
而有一些部落格說equals()是比較具體的內容是不是相同的,這個說法其實不太準確,以偏概全。這個說法的來源是很多教程都是以String類中的equals()為參照物進行舉例,String類的equals()重寫了Object物件的原始equals方法,只會比較具體的內容。
String類的equals()的具體實現程式碼如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
而 == 是比較兩個引用在記憶體中指向的是不是同一個物件,也就是在記憶體中的儲存地址是不是一樣的,兩個物件的引用相同時(指向的是同一個物件),則 == 會返回true,否則返回false。
所以 == 是和Object類的原始equals()方法是等價的。
現在很多類都對equals進行了重寫,這裡用常見的String類來編寫個測試Demo
public class TestString {
public static void main(String[] args) {
String string_1 = "codevald";
String string_2 = "codevald";
System.out.println(string_1 == string_2); //結果為true
String string_3 = new String("codevald");
String string_4 = "code" + new String("vald");
System.out.println(string_3 == string_4); //結果為false
System.out.println(string_3.equals(string_4)); //結果為true
}
}
可以看到Demo中第一個輸出語句結果為true
String string_1 = "codevald"會現在棧中建立一個對String類的引用變數string_1,然後會去字串常量池中尋找有沒有"codevald",因為是第一次建立沒有,則會將"codevald"存放進字串常量池。
String string_2 = "codevald" 又在棧中建立了String類的引用變數string_2,然後會去字串常量池中尋找有沒有"codevald",如果沒有,則會建立並存放進常量池,並將string_2指向"codevald",如果已經有了,則直接令string_2指向"codevald"。上面的程式碼已經將字串儲存進了常量池,所以兩個引用(string_1和string_2)指向同一個"codevald",返回true。
String string_3 = new String("codevald")會在堆中建立一個物件,並將在棧中存在的物件引用指向堆中的物件,而String string_4則是分別用了常量池中的字串和存放物件的堆中的字串,做 + 的時候會進行動態呼叫,最後建立完生成的物件仍然存放在堆中,而兩個物件在堆中的地址是不一樣的,所以 == 會返回false。
而String類重寫了equals方法,比較的是記憶體中存放的資料的具體內容是不是相同的,這裡存放的都是"codevald",所以會返回true。
總結
對於字串變數來說,使用""和"equals"比較字串時,其比較方法不同。""比較兩個變數本身的值,即兩個物件在記憶體中的首地址,"equals"比較字串包含內容是否相同。
對於非字串變數來說,如果沒有對equals()進行重寫的話,"==" 和 "equals"方法的作用是相同的,都是用來比較物件在堆記憶體中的首地址,即用來比較兩個引用變數是否指向同一個物件。