看板 java 關於我們 聯絡資訊
我只討論觀念。 ※ 引述《Killercat (殺人貓™)》之銘言: : ※ 引述《noapaov (單身漢)》之銘言: : : 最近看了一下書籍, 不太清楚理解是否有錯, 想請教一下各位 : : Object 類別所提供的 hashCode() method, 主要是返回物件的記憶體位置 : : 經過運算後的整數, 所以與記憶體有密切關係 : : 所以每個物件的HashCode()理論上應該都不一樣, 但是有些子類別繼承後會 : : 進行equals和HashCode的覆寫,例如String、Array等, 所以就有可能造成 : : : 如果兩個物件使用equals(Object) 測試結果為不相等, : : 則這兩個物件呼叫 hashCode 時,可以獲得不同的整數結果("可以相同,也可以不同") : : 所以總結是如果繼承Object類的子類別, 沒有對equals hashCode進行改寫, : : 那麼這些物件產生的HashCode應該都不一樣, 但如果重寫就有可能造成HashCode相等, 但不一定是參考相同的記憶體位置情況 : : 不知道原理是否是這樣 : 回文一下好了,我簡單說一下 : 1. hashCode()不見得跟記憶體位置有關,有興趣翻一下OpenJDK的String.hashCode() : 他的實作方式保證你看了會笑出來 : http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/ : classes/java/lang/String.java 覆寫方法。 : 縮 : http://tinyurl.com/mqguft4 : 2. 追下去原始碼的話你會發現 Object的hashCode是native : 但是你只要對現代Java的GC有一點認識的話,就知道GC是會搬動記憶體的 : 從Java6引入Hotspot GC以降,整個heap被分為young/old/permgen : http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/ 這是對的,有手動去調整或看過eclipse.ini就可以知道。 : 也就是說,你一個object的物件在記憶體裡面的位置根本是會跑來跑去的 : 他的hash會因此變來變去嗎?不會。 這個部分問題會變成你覺得物件的hashCode會永遠不變嗎? 我的主張是會變的。 : 那你覺得hashCode跟記憶體有沒有關係呢? : 目前來講「應該」是沒有,不然按這種搬法,要是有第二個object出現在heap同位置 : 那不就死翹翹了? 問題變成當第二個object出現的時候,第一個object的位置在那裏呢? 如果位置相同-->以現今的計算機架構有這種可能嗎?我主張沒有。 如果位置不同的話-->那hashCode會一樣嗎? 我主張不會。 更精確地我的本意為要以hashCode當作identifier時,就不應該讓他會。 讓他會一定是有特殊意義或特殊用途"故意"讓他一樣。 或是存在一種可能是覆寫這個hashCode()內容寫得很爛,容易產生一樣的結果。 : 我提供一下OpenJDK hashCode()的native C code給你參考一下 : 不同JVM有不同實作,不過我想再有implement Hotspot的JVM下 : 我想應該僅僅只是一個序列號而已 : http://tinyurl.com/mhhrehs (他實作請搜尋get_next_hash,可以對照.h去對簽名) : 在OpenJDK的VM實作,我們可以清楚地看到他其實只是一個遞增序列 : ok...這看不懂沒關係 : 總之,雖然我沒有Oracle JVM的原始碼,但是我想....那本書應該是錯的 : 這東西跟記憶體位置毫無關係 : 其實有興趣可以去翻一下 以不同JVM會有不同實作的情況下, 你的回答是"hashCode()不見得跟記憶體位置有關" 不見得類似於不一定,就變成Y and N,可Y可N,真的難以討論。 爭議點會是所謂的internal address一詞的解釋是? 沒有討論出結果,而且還會被反問為什麼要知道。 http://stackoverflow.com/questions/16105420/ java-object-hashcode-address-or-random 提供google關鍵字 java object.hashcode memory address java object hashcode changes java object hashcode implementation 眾多討論指向stackoverflow.com, 是個好網站。 但如果看完討論追一下回應(不只是回覆,還要看回覆的回覆,小字的那種) 還真的頗好笑的。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.248.170.63 ※ 文章網址: https://www.ptt.cc/bbs/java/M.1432545279.A.9C1.html
Killercat: OpenJDK原始碼來講不會變,spec的話要找找 05/25 17:58
Killercat: 另外hashCode會變動的話會有很奇怪的事情發生 05/25 17:59
Killercat: 你會在thread裡面赫然發現自己沒辦法等於自己... 05/25 17:59
Killercat: 因為你存下來的hashCode已經不能作準了 05/25 17:59
嗯。 "你會在thread裡面赫然發現自己沒辦法等於自己..." 這句是我沒看懂的地方,概念上模糊,你可以選擇是否進一步解釋。但我不會追問。 我以 https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html 其中public int hashCode() 有一句寫著 Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application. 我不翻譯整段因為不想強調英文。 只講need not remain consistent為"不需要維持一致" ※ 編輯: pttworld (111.248.170.63), 05/25/2015 18:11:11
Killercat: 上面有板友提到一個更好的例子 : HashMap 05/25 18:10
Killercat: HashTable...er..一樣啦 05/25 18:11
Chikei: 通常來說啦,會不會變來變去是討論你引的這段話的第一句 05/25 18:12
Chikei: 在單一JVM生命週期內,要扯到不同次JVM生命週期的話只能說 05/25 18:12
Chikei: 你高興就好,但是請註明。 05/25 18:12
Killercat: 他的意思是說,在同一個jvm週期必須相等,而不同jvm 05/25 18:13
Chikei: 再來Killercat原文舉的例子是用單一週期內GC的行為 05/25 18:13
Killercat: 週期不需要相等。我想我們討論應該都是以同JVM週期為 05/25 18:13
Killercat: 前提,對吧? 05/25 18:13
好的, 所以同JVM週期hashCode值相同且記憶體搬來搬去 = hashCode()和記憶體位置毫無關係? 這樣?
Killercat: 另外threading的問題比較複雜難解釋,不如hash table 05/25 18:15
Killercat: 那麼簡單易懂,我會說是我例子舉得比較難懂 XD 05/25 18:15
Killercat: 我只是想說,Thread實作通常會把自己Thread ID記下來 05/25 18:15
Killercat: 這個thread ID通常就是hashCode,要是會變來變去的話 05/25 18:16
Killercat: 那你會連出去的Thread在哪都找不到 05/25 18:16
Killercat: 這例子真的舉得有夠爛,所以還是Chikei的例子比較好 05/25 18:17
http://stackoverflow.com/questions/13860194/ what-is-an-internal-address-in-java hotspot/src/share/vm/runtime/synchronizer.hpp http://stackoverflow.com/questions/557574/ what-is-native-implementation-in-java/565416 ※ 編輯: pttworld (111.248.170.63), 05/25/2015 19:27:48
Killercat: 目前沒開compiler下 我無法得知get_next_hash()裡面 05/25 19:32
Killercat: hashCode到底是什麼(看起來比較像Type) 05/25 19:32
Killercat: 但是扣掉純粹拿ptr那個以及拿ptr併一個random計算以外 05/25 19:33
Killercat: 其他的case看起來都不像有參考到obj的位置 05/25 19:33
Killercat: 另外說真的internal address就看spec有沒有這個literal 05/25 19:34
Killercat: 的定義就一翻兩瞪眼了... 有空再查查看 05/25 19:34
Killercat: 另外 obj會游移這個是沒問題的 游移hashCode不會跟著 05/25 19:35
Killercat: 變我想也是確定的(這個原始碼還挺清楚的) 所以這兩點 05/25 19:35
Killercat: 姑且先當已經確定的共識吧 05/25 19:36
Killercat: 不過我前一篇有非常明確的指名為什麼我不認為他跟記憶 05/25 19:37
Killercat: 有關,因為他會動,所以要是新的object在已經被移走的 05/25 19:37
Killercat: 舊object上產生呢?src裡面有一個case是說他是拿記憶體 05/25 19:38
Killercat: 位置在對一個亂數mask作bitwise計算,這種前提下我不覺 05/25 19:38
Killercat: 的這叫做「跟記憶體位置有關」 05/25 19:38
if (hashCode == 1) { // This variation has the property of being stable (idempotent) // between STW operations. This can be useful in some of the 1-0 // synchronization schemes. intptr_t addrBits = intptr_t(obj) >> 3 ; value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ; } else if (hashCode == 2) { value = 1 ; // for sensitivity testing } else if (hashCode == 3) { value = ++GVars.hcSequence ; } else if (hashCode == 4) { value = intptr_t(obj) ; } 大概就1和4吧,intptr_t有疑問。 只就字義上斷章取義只看ptr想成是指標好了, 那又想成c語言好了, 對於一個ptr隨便亂加好了, 到底加的這個計算是在加什麼的問題。 就當我亂想好了,反正我決定我該停在這裡就是了。 ※ 編輯: pttworld (111.248.170.63), 05/25/2015 19:45:34
Killercat: 1就是我說的「我不認為這稱為記憶體位置」 05/25 20:59
3大概也不是
Killercat: 3是明顯的serial sequence啊 XD 05/26 08:38
好。 ※ 編輯: pttworld (111.248.172.93), 05/26/2015 08:39:58
swpoker: jvm當初的目的就是希望寫程式可以不用管記憶體 05/26 15:52
swpoker: 寫程式的時候,"不用先要塊記憶體來使用" "不用知道位置" 05/26 15:53
swpoker: 希望只要專注在程式本身,而記憶體這種事就交給VM就好 05/26 15:55
是。 VM以外。 ※ 編輯: pttworld (111.248.172.93), 05/26/2015 15:56:17