一、目的
經典面試題,自己動手剖析,用於個人記錄共同學習。
二、equals簡介
1.equals和==區別
1.==
String str1 = "string";
String str2 = new String("string");
boolean b = str1 == str2;//false
這裏str1==str2比較的是對象的引用地址是否指向的是同一個對象。
== 比較的是變量(棧)內存中存放的對象的(堆)內存地址,用來判斷兩個對象的地址是否相同,即是否是指相同一個對象。比較的是真正意義上的指針操作
引用地址:
public class TestDemo {
public static void main(String[] args) {
String str1 = "string";
String str2 = new String("string");
System.out.println(toString(str1));//java.lang.String@914504136
System.out.println(toString(str2));//java.lang.String@166239592
}
public static String toString(String str) {
return str.getClass().getName() + "@" + System.identityHashCode(str);
}
}
2.equals
先看一下Object的equals方法
public boolean equals(Object obj) {
return (this == obj);
}
Object的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重寫的equals方法進行對比。
小結:equals()和 == 有着本質的區別,== 可以看作是對“操作系統比較數據手段”的封裝,而equals()則是每個對象自帶的比較方法,它是Java自定義的比較規則。
三、hashCode簡介
hashCode是哈希值,哈希值是通過哈希函數計算得來的。
哈希函數能夠保證相同的輸入能夠得到相同的輸出(哈希值),但是不能夠保證不同的輸入總是能得出不同的輸出。
hashCode的存在主要是用於查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中確定對象的存儲地址的。
四、淺談hashCode和equals
Map和Set集合都是不允許元素重複的,嚴格來說Map存儲的是鍵值對,它不允許重複的鍵值。
這些容器在存儲元素的時必須對元素做出判斷:在當前的容器中有沒有和新元素相同的元素。
Map 和 Set 的絕大多數實現類的底層都會用到散列表結構。
如果直接用equals判斷重複,時間複雜度爲O(n),但在散列表的基礎上,判斷是否重複就容易得多了。
我們不妨假設兩個相同的對象,hashCode() 一定相同,這麼一來就體現出哈希函數的威力了。
由於相同的輸入一定會產生相同的輸出,於是如果新對象,和容器中已存在的對象相同,新對象計算出的哈希值就會和已存在的對象的哈希值產生衝突。這時容器就能判斷:這個新加入的元素已經存在,需要另作處理:覆蓋掉原來的元素(key)或捨棄。
按照這個思路,如果這個元素計算出的哈希值所對應的內存單元沒有產生衝突,也就是沒有重複的元素,那麼它就可以直接插入。所以當運用 hashCode() 時,判斷是否有相同元素的代價,只是一次哈希計算,時間複雜度爲O(1),這極大地提高了數據的存儲性能。
五、hashCode和equals關係
不同的參數可能會輸出相同的哈希值,也就是形成哈希衝突,這樣一來就需要equals進行二次判斷是否相同。
這也是爲什麼 Java 官方推薦我們在一個類中,最好同時重寫 hashCode() 和 equals() 方法的原因。
hashCode和equals規則
- 如果兩個對象是相等的,它們的 equals() 方法應該要返回 true,它們的 hashCode() 需要返回相同的結果;
- 如果equals方法得到的結果爲false,則兩個對象的hashcode值不一定不同;
- 如果兩個對象的hashcode值不等,則equals方法得到的結果必定爲false;
- 如果兩個對象的hashcode值相等,則equals方法得到的結果不一定相等;