==: 比較的是變量(棧)內存中存放的對象的(堆)內存地址,用來判斷兩個對象的地址是否相同,便是否是指相同一個對象。比較的是真正意義上的指針操做。html
equals:用來比較的是兩個對象的內容是否相等,因爲全部的類都是繼承自java.lang.Object類的,因此適用於全部對象,String中的類是重寫了object類裏的equal()方法,而在本來的object類中,返回的是==的判斷,若是沒有對該方法進行覆蓋的話,調用的仍然是Object類中的方法。java
hashCode : Object 的 native方法 , 獲取對象的哈希值,用於肯定該對象在哈希表中的索引位置,它其實是一個int型整數。算法
在Java中有八種基本數據類型:數組
浮點型:float(4 字節), double(8 字節)this
整型:byte(1 字節), short(2 字節), int(4 字節) , long(8 字節)spa
字符型: char(2 字節).net
布爾型: boolean設計
對於這八種基本數據類型的變量,變量直接存儲的是「值」,基本數據類型之間的比較須要用雙等號(==),由於他們比較的是值指針
接口、類、數組等非基本數據類型code
Java中的字符串String屬於引用數據類型。由於String是一個類
引用類型的變量存儲的並非「值」自己,而是與其關聯的對象在內存中的地址,當他們用(==)進行比較的時候,比較的是他們在內存中的存放地址,因此,除非是同一個new出來的對象,他們的比較後的結果爲true,不然比較後結果爲false。由於每new一次就會從新開闢一個新的堆內存空間
String s1 = "小新";
String s2 = "小新";
System.out.println(s1 == s2); //true
String str1 = new String("小新");
String str2 = new String("小新");
System.out.println(s1 == str1); //false
System.out.println(str1 == str2); //false
複製代碼
s1 == s2爲true,是由於s1和s2都是字符串字面值"小新"的引用,指向同一塊地址,因此相等。
s1== str1爲false,是由於經過new產生的對象在堆中,str1是堆中變量的引用,而s1是指向字符串字面值"小新"的引用,地址不一樣因此不相等。
str1 == str2爲flase,是由於即便內容相同,因爲不是指向同一個對象,也會返回false。
equals,是Objec類的方法,源代碼以下:
public boolean equals(Object obj) {
return (this == obj);
}
複製代碼
可見Objec的equals方法,直接調用==,比較對象地址,便是否指向同一個對象。
不一樣的子類,能夠重寫此方法,進行兩個對象的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;
}
複製代碼
使用equals方法,內部實現分爲三個步驟:
所以,對於 equals 方法:
hashCode 方法是基類Object中的 實例native方法,所以對全部繼承於Object的類都會有該方法。
他的源碼以下:
public native int hashCode();
複製代碼
說明是一個本地方法,它的實現是根據本地機器相關的。固然咱們能夠在本身寫的類中覆蓋hashcode()方法,好比String、Integer、Double等這些類都是覆蓋了hashcode()方法的。例如在String類中定義的hashcode()方法以下:
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31 * h + val[off++];
}
hash = h;
}
return h;
}
複製代碼
想要弄明白hashCode的做用,必需要先知道Java中的集合。 總的來講,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。前者集合內的元素是有序的,元素能夠重複;後者元素無序,但元素不可重複。這裏就引出一個問題:要想保證元素不重複,可兩個元素是否重複應該依據什麼來判斷呢? 這就是Object.equals方法了。可是,若是每增長一個元素就檢查一次,那麼當元素不少時,後添加到集合中的元素比較的次數就很是多了。也就是說,若是集合中如今已經有1000個元素,那麼第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大下降效率。
因而,Java採用了哈希表的原理。哈希(Hash)其實是我的名,因爲他提出一哈希算法的概念,因此就以他的名字命名了。哈希算法也稱爲散列算法,是將數據依特定算法直接指定到一個地址上,初學者能夠簡單理解,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能並非)。
這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一會兒能定位到它應該放置的物理位置上。若是這個位置上沒有元素,它就能夠直接存儲在這個位置上,不用再進行任何比較了;若是這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。因此這裏存在一個衝突解決的問題。這樣一來實際調用equals方法的次數就大大下降了,幾乎只須要一兩次。
1.使用hashcode方法提早校驗,能夠避免每一次比對都調用equals方法,提升效率
2.保證是同一個對象,若是重寫了equals方法,而沒有重寫hashcode方法,會出現equals相等的對象,hashcode不相等的狀況,重寫hashcode方法就是爲了不這種狀況的出現。