小菜毛毛技術分享

          與大家共同成長

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            164 Posts :: 141 Stories :: 94 Comments :: 0 Trackbacks

          常用鏈接

          留言簿(15)

          我參與的團隊

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          經常在論壇上面看到覆寫hashCode函數的問題,很多情況下是一些開發者不了解hash code,或者和equals一起用的時候不太清楚為啥一定要復寫hashCode。

              對于hash code的理論我不想多說,這個話題太大。我只想說用hash code的原因只有一個:效率。理論的說法它的復雜度只有O(1)。試想我們把元素放在線性表里面,每次要找一個元素必須從頭一個一個的找它的復雜度有O(n)。如果放在平衡二叉樹,復雜度也有O(log n)。

             為啥很多地方說“覆寫equals的時候一定要覆寫hashCode”。說到這里我知道很多人知道有個原則:如果a.equals(b)那么要確保a.hashCode()==b.hashCode()。為什么?hashCode和我寫的程序的業務邏輯毫無關系,為啥我要override? 要我說如果你的class永遠不可能放在hash code為基礎的容器內,不必勞神,您真的不必override hashCode() :)

              說得準確一點放在HashMap和Hashtable里面如果是作為value而不是作為key的話也是不必override hashCode了。至于HashSet,實際上它只是忽略value的HashMap,每次HashSet.add(o)其實就是 HashMap.put(o, dummyObject)。

              那為什么放到Hash容器里面要overide hashCode呢?因為每次get的時候HashMap既要看equals是不是true也要看hash code是不是一致,put的時候也是要看equals和hash code。

              如果說到這里您還是不太明白,咱就舉個例子:

              譬如把一個自己定義的class Foo{...}放到HashMap。實際上HashMap也是把數據存在一個數組里面,所以在put函數里面,HashMap會調 Foo.hashCode()算出作為這個元素在數組里面的下標,然后把key和value封裝成一個對象放到數組。等一下,萬一2個對象算出來的 hash code一樣怎么辦?會不會沖掉?先回答第2個問題,會不會沖掉就要看Foo.equals()了,如果equals()也是true那就要沖掉了。萬一 是false,就是所謂的collision了。當2個元素hashCode一樣但是equals為false的時候,那個HashMap里面的數組的這 個元素就變成了鏈表。也就是hash code一樣的元素在一個鏈表里面,鏈表的頭在那個數組里面。

          回過來說get的時候,HashMap也先調key.hashCode()算出數組下標,然后看equals是不是true,所以就涉及了equals。

              反觀假設如果a.equals(b)但是a.hashCode()!=b.hashCode()的話,在put元素a之后,我們又用一個 a.equals(b)但是b.hashCode()!=a.hashCode()的b元素作為key來get的時候就找不到a了。如果 a.hashCode()==b.hashCode()但是!a.equals(b)倒是不要緊,這2個元素會collision然后被放到鏈表,只是效 率變差。

            這里有個非常簡化版的HashMap實現幫助大家理解。

          1. /* 
          2.  * Just to demonstrate hash map mechanism,  
          3.  * Please do not use it in your commercial product. 
          4.  * 
          5.  * @author Shengyuan Lu 盧聲遠 <michaellufhl@yahoo.com.cn> 
          6.  */  
          7. public class SimpleHashMap {  
          8.     ArrayList<LinkedList<Entry>> entries = new ArrayList<LinkedList<Entry>>();  
          9.       
          10.     /** 
          11.      * Each key-value is encapsulated by Entry. 
          12.      */  
          13.     static class Entry {  
          14.         Object key;  
          15.         Object value;  
          16.         public Entry(Object key, Object value) {  
          17.             this.key = key;  
          18.             this.value = value;  
          19.         }  
          20.     }  
          21.     void put(Object key, Object value) {  
          22.         LinkedList<Entry> e = entries.get(key.hashCode());  
          23.         if (e != null) {  
          24.             for (Entry entry : e) {  
          25.                 if (entry.key.equals(key)) {  
          26.                     entry.value = value;// Match in lined list  
          27.                     return;  
          28.                 }  
          29.             }  
          30.             e.addFirst(new Entry(key, value));// Add the entry to the list  
          31.         } else {  
          32.             // Put the new entry in array  
          33.             LinkedList<Entry> newEntry = new LinkedList<Entry>();  
          34.             newEntry.add(new Entry(key, value));  
          35.             entries.add(key.hashCode(), newEntry);  
          36.         }  
          37.     }  
          38.     Object get(Object key) {  
          39.         LinkedList<Entry> e = entries.get(key.hashCode());  
          40.         if (e != null) {  
          41.             for (Entry entry : e) {  
          42.                 if (entry.key.equals(key)) {  
          43.                     return entry.value;  
          44.                 }  
          45.             }  
          46.         }  
          47.         return null;  
          48.     }  
          49.       
          50.     /** 
          51.      * Do we need to override equals() and hashCode() for SimpleHashMap itself?  
          52.      * I don't know either:) 
          53.      */  
          54. }  


          這個問題的權威闡釋可以參考Bloch的<Effective Java>的 Item 9: Always override hashCode when you override equals

          posted on 2010-08-27 09:51 小菜毛毛 閱讀(398) 評論(0)  編輯  收藏 所屬分類: 面試
          主站蜘蛛池模板: 土默特左旗| 北京市| 达日县| 山东| 定南县| 廊坊市| 建瓯市| 承德县| 娄烦县| 嵩明县| 文昌市| 淮阳县| 宝坻区| 旬阳县| 西青区| 浦东新区| 平果县| 容城县| 湖北省| 吴旗县| 武宁县| 汨罗市| 习水县| 报价| 肃宁县| 凤山市| 高邮市| 澎湖县| 岳阳市| 正定县| 易门县| 色达县| 遂宁市| 五莲县| 莆田市| 库尔勒市| 望城县| 常州市| 洛宁县| 迭部县| 汝城县|