說一下我的思考(都待商榷且不好驗證,請各位指點):首先,我們應該搞清楚一個順序順序問題,我認為,一個物件是在實體化后先被new出來,放在地址中,然后再去計算它的hashcode,用這個hashcode只是作為java中的這個物件的一個標識。也就是說,只要new一次就會產生一個物件(聽起來像是廢話,但是細細品),就是說,無論物件里的值相不相等,都是不同的物件,然后==(這個符號),是比較的兩個物件的地址,即物件在jvm的堆里面的地址(我認為是比較的一個地址數值直接是計算機的儲存這個物件記憶體的起始地址),我們一般比較是把這個物件用一個參考變數參考,比方說User user= new User(“鬼谷”,“22”);其中,user就是參考變數,把它存放到jvm的堆疊中,而new User(“鬼谷”,“22”)這是new的一個物件,放在堆中,堆疊是進行邏輯執行的,而堆是放東西的,這里就是將new User(“鬼谷”,“22”)的地址的值給了user,表現為user指向new User(“鬼谷”,“22”),我認為user本身的地址是讓作業系統處理,通過入堆疊彈堆疊進行程式運行,而==進行比較的時候就,就是通過比較講個參考物件的值來判斷是否相等,這時參考物件的值就是他只指向的物件的起始地址,如果是指向的同一個物件值就相等,反之不相等。插一段,為下面鋪墊,我認為(只要是我認為就是不確定,希望各位確定是這么回事的明確一下)對于基本資料型別,如果是在方法里的,放在堆疊中,在運行程式的時候即拿即用(感覺這就是為什么在方法里不能定義方法的作用域的原因),而在類里面的基本資料型別,作為屬性,應該是new出來以后放在堆里面,等到運行的時候從堆里拿出,表現為方法里如果參考了這個物件,就會把這個的屬性的值賦值給方法里定義的一個變數,如方法中:int i = user.getAge();user.getAge()是從堆里面的到這個值,而i是在堆疊里面,如果是直接進行比較如 user.getAge()== user1.getAge(),則是將兩個值取出,放在堆疊中,比較兩個基本變數數值的大小,即比較它們的二進制碼,做一個小說明,我認為在堆疊中,基本型別和參考物件都是一個二進制碼,表現形式不同,基本資料型別存的是值,例如int i =1;就是代表堆疊中存了1這個值(在堆疊中這個位置放的就是這個二進制碼,前幾位是0,后4位就是0001),而參考型別,則是存放在堆中物件的地址。而==就是比較這兩個物件二進制碼是否相同,即它比較的是堆物件的起始地址。接著說hashcode,在hashcode沒有被重寫前,是根據jvm堆里面這個物件的地址,計算出來的一個數值,在java中用于標識這個物件的地址(我認為這個可能不是唯一的,不同的物件計算出來的hashcode可能相同),和重寫以后,如return Objects.hash(id, name, munber);這樣就是根據new出來的物件的屬性的數值,去計算hashcode,好多人覺得這個值和用equals比較大小密不可分,但是我覺得這兩者并沒有什么關系,無論是equal重寫前還是重寫后,自始至終從未提到過hashcode(或許我沒找到,要是哪位找到了,煩請告知),hashcode在重寫后(默認的重寫方法,將所有屬性都放入hash的引數中)就是判斷兩個物件的屬性是否一樣,
例如不同的兩個類new兩個屬性相同的物件,如果屬性值和hashcode的重寫方式方式相同,則hashcode也相同,什么也說明不了,最多判斷兩個物件一定不相等。最后是equals,這個和==有對比性,沒有重寫前為return (this == obj);說明兩個效果相同,但是重寫后如下:

equals重寫后,首先判斷這兩個參考物件的參考地址是否一樣,如果相同說明是參考堆里面的同一個物件(因為==比較的真實的地址),同一個物件,沒有疑問,一定相同;否則,接著運行方法,根據反射判斷是否來自同一個Class類,就避免了不同類屬性相同和屬性值的問題,這就是比hashcode高明的地方,如上面hashcode的例子,即使不是一個物件也出現hashcode相同的情況。接著,如果相同,就進行接下來的比較,基本型別用==比較,在基本型別中,如果數值相同則回傳true,上面已經做了闡述,非基本型別用equals比較,但是歸根結底還是用==比較,沒有hashcode的任何關系,所以我就產生疑惑為什么重寫equals要重寫hashcode?
以上就是我對==、hashcode、equals的粗知薄見,有不對的地方懇求各位一定指出。
uj5u.com熱心網友回復:
基本上可以說:hashCode主要用于提升查詢效率提高哈希表性能,來確定在散列結構中物件的存盤地址
1、重寫equals()必須重寫hashCode()
2、哈希存盤結構中,添加元素重復性校驗的標準就是先檢查hashCode值,后判斷equals()
3、兩個物件equals()相等,hashcode()必定相等
4、兩個物件hashcode()不等,equals()必定也不等
5、兩個物件hashcode()相等,物件不一定相等,需要通過equals()進一步判斷。
重寫equals之后必須重寫hashcode的目的是為了保證equals相同的物件在hashmap/hashset的同一個哈希桶中,從而提高檢索速度。
uj5u.com熱心網友回復:
我覺得樓主是誤解了hashCode的用法。 一個物件的hashcode 是為了確定這個物件的唯一性,最完美的解決方案就是每一個實體化的物件都有一個完全唯一的hash code作為他的唯一性標簽。但是這種“唯一性”很難被實作,所以就有了一個妥協的約定:如果兩個物件的實體是相同的 a.equals(b) == true 那 a 和 b的hash code一定相同。但是如果a.equals(b) == false, 他們的hashCode 也可能相同。Hash Code 主要用在以hash 實作的資料結構里尋找鍵所對應的值,目的是搜索并回傳目標物件的實體。其中最常用的就是hashmap. 你可以把hashmap 想象成一排桶,每一個桶的標簽就代表了一個希哈值。如果按照最完美的狀況,每個hash code 值都是唯一的,那每個桶里就只有一個實體,就會很快速的找到。但現實可能是每個桶里有多個元素,當找到那個桶之后,系統還需要根據equals 方法從多個元素里找到對應的實體。
java 提供了Comparator / Comparable 介面去實作實體的比較
uj5u.com熱心網友回復:
“為什么重寫equals要重寫hashcode”
因為有一個重要的規范:equals回傳true的兩個物件,他們的hashcode必須一樣
所以如果你僅僅只重寫了equals,那么很可能hashcode回傳的值是不一樣的
這樣的話,在ArrayList這類陣列型集合中似乎看不出什么問題
但是如果是HashMap的key,那么問題就暴露出來了
這可不僅僅是檢索速度快慢的問題
而是你很可能根本無法從HashMap中獲得你期望得到的那個元素
你看一下HashMap中get的原始碼:
public synchronized V get(Object key) {
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
return null;
}
重點是這一句: if ((e.hash == hash) && e.key.equals(key)) {
如果你的物件是作為 HashMap 的 key 的話
是先要判斷 hashcode 的
HashSet 也有同樣問題,先判斷hashcode
如果hashcode 不一樣,就已經認為是不同物件了,
也就是你 equals 為 true 的兩個物件如果hashcode不一樣,會重復存在于 Set 中,違背了Set的意義
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/100444.html
標籤:Java SE
上一篇:MySQL連接的一些問題
