<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    走在架構師的大道上 Jack.Wang's home

    Java, C++, linux c, C#.net 技術,軟件架構,領域建模,IT 項目管理 Dict.CN 在線詞典, 英語學習, 在線翻譯

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      195 Posts :: 3 Stories :: 728 Comments :: 0 Trackbacks
    為什么HashCode對于對象是如此的重要?

      一個對象的HashCode就是一個簡單的Hash算法的實現,雖然它和那些真正的復雜的Hash算法相比還不能叫真正的算法,它如何實現它,不僅僅是程序員的編程水平問題,而是關系到你的對象在存取是性能的非常重要的關系.有可能,不同的HashCode可能會使你的對象存取產生,成百上千倍的性能差別。

      我們先來看一下,在JAVA中兩個重要的數據結構:HashMap和Hashtable,雖然它們有很大的區別,如繼承關系不同,對 value的約束條件(是否允許null)不同,以及線程安全性等有著特定的區別,但從實現原理上來說,它們是一致的.所以,我們只以Hashtable 來說明:

      在java中,存取數據的性能,一般來說當然是首推數組,但是在數據量稍大的容器選擇中,Hashtable將有比數組性能更高的查詢速度.具體原因看下面的內容。

      Hashtable在存儲數據時,一般先將作為key的對象的HashCode和0x7FFFFFFF做與操作,因為一個對象的 HashCode可以為負數,這樣操作后可以保證它為一個正整數.然后以Hashtable的長度取模,得到值對象在Hashtable中的索引。

      index = (o.hashCode() & 0x7FFFFFFF)%hs.length;這個值對象就會直接放在Hashtable的第index位置,對于寫入,這和數組一樣,把一個對象放在其中的第index位置,但如果是查詢,經過同樣的算法,Hashtable可以直接通過key得到index,從第index取得這個值對象,而數組卻要做循環比較.所以對于數據量稍大時,Hashtable的查詢比數據具有更高的性能。

      雖然不同對象有不同的hashcode,但不同的hashCode經過與長度的取余,就很可能產生相同的index。

      極端情況下會有大量的對象產生一個相同的索引.這就是關系Hashtable性能問題的最重要的問題:

      Hash沖突。

      常見的Hash沖突是不同key對象最終產生了相同的索引,而一種非常甚至絕對少見的Hash沖突是,如果一組對象的個數大過了int 范圍,而HashCode的長度只能在int范圍中,所以肯定要有同一組的元素有相同的HashCode,這樣無論如何他們都會有相同的索引.當然這種極端的情況是極少見的,可以暫不考慮,但是對于同的HashCode經過取模,則會產中相同的索引,或者不同的對象卻具有相同的HashCode,當然具有相同的索引。

      事實上一個設計各好的HashTable,一般來說會比較平均地分布每個元素,因為Hashtable的長度總是比實際元素的個數按一定比例進行自增(裝填因子一般為0.75)左右,這樣大多數的索引位置只有一個對象,而很少的位置會有幾個元素.所以Hashtable中的每個位置存放的是一個鏈表,對于只有一個對象是位置,鏈表只有一個首節點(Entry),Entry的next為null.然后有 hashCode,key, value屬性保存了該位置的對象的HashCode,key和value(對象本身),如果有相同索引的對象進來則會進入鏈表的下一個節點.如果同一個索引中有多個對象,根據HashCode和key可以在該鏈表中找到一個和查詢的key相匹配的對象。

      從上面我看可以看到,對于 HashMap和Hashtable的存取性能有重大影響的首先是應該使該數據結構中的元素盡量大可能具有不同的HashCode,雖然這并不能保證不同的HashCode產生不同的index,但相同的HashCode一定產生相同的index,從而影響產生Hash沖突。

      對于一個象,如果具有很多屬性,把所有屬性都參與散列,顯然是一種笨拙的設計.因為對象的HashCode()方法幾乎無所不在地被自動調用,如equals比較,如果太多的對象參與了散列.那么需要的操作常數時間將會增加很大.所以,挑選哪些屬性參與散列絕對是一個編程水平的問題。

      從實現來說,一般的HashCode方法會這樣:

      return Attribute1.HashCode() + Attribute1.HashCode()..[+super.HashCode()]。

      我們知道,每次調用這個方法,都要重新對方法內的參與散列的對象重新計算一次它們的HashCode的運算,如果一個對象的屬性沒有改變,仍然要每次都進行計算,所以如果設置一個標記來緩存當前的散列碼,只要當參與散列的對象改變時才重新計算,否則調用緩存的hashCode,這可以從很大程度上提高性能。

      默認的實現是將對象內部地址轉化為整數作為HashCode,這當然能保證每個對象具有不同的HasCode,因為不同的對象內部地址肯定不同(廢話),但java語言并不能讓程序員獲取對象內部地址,所以,讓每個對象產生不同的HashCode有著很多可研究的技術。

      如果從多個屬性中采樣出能具有平均分布的hashCode的屬性,這是一個性能和多樣性相矛盾的地方,如果所有屬性都參與散列,當然 hashCode的多樣性將大大提高,但犧牲了性能,而如果只能少量的屬性采樣散列,極端情況會產生大量的散列沖突,如對"人"的屬性中,如果用性別而不是姓名或出生日期,那將只有兩個或幾個可選的hashcode值,將產生一半以上的散列沖突.所以如果可能的條件下,專門產生一個序列用來生成 HashCode將是一個好的選擇(當然產生序列的性能要比所有屬性參與散列的性能高的情況下才行,否則還不如直接用所有屬性散列)。

      如何對HashCode的性能和多樣性求得一個平衡,可以參考相關算法設計的書,其實并不一定要求非常的優秀,只要能盡最大可能減少散列值的聚集.重要的是我們應該記得HashCode對于我們的程序性能有著生要的影響,在程序設計時應該時時加以注意。

    原文地址:http://xy-z487.javaeye.com/blog/238074




    本博客為學習交流用,凡未注明引用的均為本人作品,轉載請注明出處,如有版權問題請及時通知。由于博客時間倉促,錯誤之處敬請諒解,有任何意見可給我留言,愿共同學習進步。
    posted on 2008-09-08 20:53 Jack.Wang 閱讀(5258) 評論(2)  編輯  收藏 所屬分類: 開發技術數學&算法

    Feedback

    # re: 為什么HashCode對于對象是如此的重要? 2008-09-25 11:21 zhuxing
    "但相同的HashCode一定產生相同的index,從而影響產生Hash沖突"
    這句話比較有用  回復  更多評論
      

    # re: 為什么HashCode對于對象是如此的重要? 2012-07-30 11:54 實得分
    寫些什么垃圾 放了一堆屁  回復  更多評論
      

    主站蜘蛛池模板: 亚洲中文无码永久免费| 亚欧在线精品免费观看一区| 四虎在线免费播放| 亚洲sss综合天堂久久久| 在线看片无码永久免费视频 | 国产三级免费观看| 蜜芽亚洲av无码一区二区三区| 最新中文字幕电影免费观看| 亚洲人AV在线无码影院观看| 蜜桃精品免费久久久久影院| 国产精品亚洲专区无码WEB| 国产极品粉嫩泬免费观看| 免费又黄又爽又猛大片午夜| 亚洲人成无码网WWW| baoyu777永久免费视频 | 亚洲激情黄色小说| 中文字幕人成无码免费视频| 亚洲av午夜国产精品无码中文字 | 亚洲一区二区三区乱码在线欧洲| 希望影院高清免费观看视频| 亚洲日本VA中文字幕久久道具| 四虎影视永久免费观看| 在线免费观看h片| 亚洲精品永久www忘忧草| 中文字幕av无码无卡免费 | 最近免费字幕中文大全| 亚洲黄色网址在线观看| 性一交一乱一视频免费看| 十八禁的黄污污免费网站| 亚洲开心婷婷中文字幕| 免费三级毛片电影片| 亚洲av日韩综合一区二区三区| 三上悠亚亚洲一区高清| 永久免费视频网站在线观看| 亚洲熟妇少妇任你躁在线观看| 亚洲午夜日韩高清一区| 亚洲免费福利视频| 青青草国产免费国产是公开| 777亚洲精品乱码久久久久久 | 成人精品视频99在线观看免费| 亚洲精品在线视频观看|