Heis的Blog

          保持簡單,保持愚蠢
          隨筆 - 29, 文章 - 1, 評論 - 122, 引用 - 0
          數(shù)據(jù)加載中……

          大話深入淺出Effective Java核心實戰(zhàn)編程思想之——那些雞翅

              好吧好吧,我承認(rèn)這有點標(biāo)題黨的嫌疑,我這不是隔太久沒更新,有點興奮么。
              板磚拍夠了,臭雞蛋扔夠了,別來打醬油便行了。我這就進(jìn)入正題。其實正確的標(biāo)題應(yīng)該叫Effective Java讀書心得之雞翅的故事。

              關(guān)于雞翅的故事,相傳最近最近以前……
           1 import static org.junit.Assert.*;
           2 
           3 import java.util.HashMap;
           4 
           5 import org.junit.Test;
           6 
           7 
           8 public class TestObjectHashCode {
           9     
          10     @Test
          11     public void testIt(){
          12           //最近,麥當(dāng)當(dāng)推出了麥香翅,味道不是一般的好,那是相當(dāng)?shù)暮谩?br /> 13           //于是受到消費者的青睞,大受歡迎。
          14           雞翅 麥香翅=new 雞翅("麥香翅");
          15           味道 味道好極了=new 味道("味道好極了");
          16           HashMap 市場=new HashMap();
          17           市場.put(麥香翅, 味道好極了);
          18           
          19           //這一切都被一個山寨小食店看在眼里,他們決定打著麥香翅的名號,推出實際上味道一般的山寨麥香翅
          20           雞翅 山寨麥香翅=new 雞翅("麥香翅");            
          21           
          22           //山寨小食店的師傅還是很有智慧的,他們通過某某方式,通過ISO叉叉叉叉的認(rèn)證。
          23           //他們很天真地認(rèn)為他們的山寨翅可以媲美麥香翅。
          24           assertTrue(山寨麥香翅.equals(麥香翅)); 
          25           
          26           //但是結(jié)果大家都知道了,山寨翅并沒有獲得市場的認(rèn)可,魚目混珠終究被市場識別出來。
          27           assertFalse(味道好極了.equals(市場.get(山寨麥香翅)));
          28           
          29           //山寨小食店苦思瞑想,終于發(fā)現(xiàn)了問題,原來他們指打相同的名號是不行的。
          30           //他們的并沒有山寨出麥香翅代號為HashCode的秘制醬料
          31           assertFalse(麥香翅.hashCode()==山寨麥香翅.hashCode());         
          32     }
          33     
          34     public static final class 味道{
          35           private String description;
          36 
          37           public 味道(String des){
          38                 description=des;
          39           }
          40           
          41           public String getDescription() {
          42                 return description;
          43           }
          44 
          45           public void setDescription(String aDes) {
          46                 this.description = aDes;
          47           }
          48           
          49     }
          50 
          51     public static final class 雞翅 {
          52 
          53         private String Name;
          54 
          55         public 雞翅(String name){
          56               this.Name=name;
          57         }
          58         
          59         public String getName() {
          60               return Name;
          61         }
          62 
          63         public void setName(String aName) {
          64               this.Name = aName;
          65         }
          66         
          67         @Override
          68         public boolean equals(Object obj){
          69               if(!(obj instanceof 雞翅)){
          70                     return false;
          71               }
          72               return ((雞翅)obj).getName().equals(this.Name);
          73         }
          74   }
          75 
          76 }
          77 
              看完了不知道我想說啥?看來沒認(rèn)真看《Effective Java》嘛,這本書可是每個java程序員進(jìn)階必修之書,沒看過真不能自稱大蝦級別。好了,這里說到了正題的正題,其實我想說的是:

          《Effective Java》第八條:改寫equals時總是要改寫hashCode。


          *為什么要改寫hashCode
          答:(書上原話)“如果不這樣做的話,就會違反Object.hashCode的通用約定,從而導(dǎo)致該類無法與所有基于散列值(hash)的集合類在一起正常工作,這樣的集合類包括HashMap,HashSet和Hashtable.

          *那么為什么會導(dǎo)致該類無法與所有基于散列值(hash)的集合類在一起正常工作呢?
          答:且看一個HashMap的源代碼解釋。

          HashMap是通過一個叫table[]的數(shù)組來存取,table的每個元素是一個鏈表結(jié)構(gòu),鏈表的每個元素稱為 Entry<key,value>,是真正存放key和value的對象。在put的過程中,HashMap會通過特定的哈希算法將key對象的hashCode對應(yīng)到table的某個索引下,然后再用key對比鏈表中每個Entry.key,如果key相同則更新value。否則就加入新的 Entry到鏈表中。

          HashMap的數(shù)據(jù)結(jié)構(gòu)圖:




          再看一段HashMap的源代碼:
           1 public V put(K key, V value) {
           2     K k = maskNull(key);// 如果key為null則使用缺省的Object
           3         int hash = hash(k);//將k的hashCode經(jīng)過一定的計算得到新的HashCode
           4         int i = indexFor(hash, table.length);//取得HashCode在table中的位置
           5 
           6       //首先在數(shù)組內(nèi)根據(jù)key的HashCode找到Entry鏈表的第一個Entry        
           7         for (Entry<K,V> e = table[i]; e != null; e = e.next) {
           8         //如果Entry的key值HashCode相同,而且具有相同的引用或邏輯相等(equals)
           9             if (e.hash == hash && eq(k, e.key)) {
          10             //將新的value放入Entry中,返回舊的value
          11                 V oldValue = e.value;
          12                 e.value = value;
          13                 e.recordAccess(this);
          14                 return oldValue;
          15             }
          16         }
          17       
          18         //修改次數(shù)加1
          19         modCount++;
          20       //在table的第i個位置的鏈表后加上一個新的Entry
          21         addEntry(hash, k, value, i);
          22         return null;
          23 }
          24 
          25 static boolean eq(Object x, Object y) {
          26         return x == y || x.equals(y);
          27     }
          28 

          *最后來看java.lang.Object的約定(經(jīng)過自己語言描述,原話自己看書去)
          1.如果一個類的equals方法所用到的信息(邏輯相等的條件因素)沒有被修改的話,那么它hashCode也不會改變。換個角度來看,也就是說,hashCode返回值最好與equals方法所用到的信息相關(guān)。

          2.如果兩個實例根據(jù)equals對比是相等的,那么它們的HashCode相等。

          3.如果兩個實例根據(jù)equals對比是不相等的,那么它們的HashCode最好是不等,這對于Hash性能的提高有好處。

          E.g 如果Person實例的ID屬性沒有被修改的話,那么它的HashCode也不會改變
           1 public class Person{
           2         private String ID;
           3         public boolean equals(Object obj){
           4              if(!(obj instanceof Person)&& ((Person)obj).getID()!=null){
           5                 return false;
           6         }
           7             return ((Person)obj).getID().equals(this.ID);
           8         }
           9 
          10         public int hashCode(){
          11             if(ID==null){
          12                 return 23;
          13             }else{
          14                 return ID.hashCode();
          15             }
          16         }
          17         public String getID() {
          18             return ID;
          19         }
          20         public void setID(String id) {
          21             ID = id;
          22         }
          23         
          24 }
          25 


          程序員的一生其實可短暫了,這電腦一開一關(guān),一天過去了,嚎;電腦一開不關(guān),那就成服務(wù)器了,嚎……

          posted on 2009-06-20 00:59 Heis 閱讀(1703) 評論(0)  編輯  收藏 所屬分類: Effective Java

          主站蜘蛛池模板: 抚宁县| 泰州市| 文成县| 灵川县| 九龙坡区| 当涂县| 县级市| 汉川市| 栾城县| 滁州市| 遂溪县| 广东省| 张家界市| 重庆市| 博罗县| 通州区| 桓仁| 综艺| 克拉玛依市| 卓资县| 洛川县| 六盘水市| 郸城县| 高邮市| 铜川市| 蓝田县| 漯河市| 徐水县| 洛南县| 济阳县| 江华| 怀宁县| 资中县| 彰化市| 京山县| 安岳县| 拉萨市| 霸州市| 保定市| 锦州市| 中阳县|