Heis的Blog

保持简单,保持愚蠢
随笔 - 29, 文章 - 1, 评论 - 122, 引用 - 0
数据加载中……

大话深入浅出Effective Java核心实战编程思想之——那些鸡翅

    好吧好吧,我承认这有点标题党的嫌疑,我这不是隔太久没更新,有点兴奋么。
    板砖拍够了,臭鸡蛋扔够了,别来打酱油便行了。我这就进入正题。其实正确的标题应该叫Effective Java读书心得之鸡翅的故事。

    关于鸡翅的故事,相传最近最近以前……
 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           //最近,麦当当推出了麦香翅,味道不是一般的好,那是相当的好。
13           //于是受到消费者的青睐,大受欢迎。
14           鸡翅 麦香翅=new 鸡翅("麦香翅");
15           味道 味道好极了=new 味道("味道好极了");
16           HashMap 市场=new HashMap();
17           市场.put(麦香翅, 味道好极了);
18           
19           //这一切都被一个山寨小食店看在眼里,他们决定打着麦香翅的名号,推出实际上味道一般的山寨麦香翅
20           鸡翅 山寨麦香翅=new 鸡翅("麦香翅");            
21           
22           //山寨小食店的师傅还是很有智慧的,他们通过某某方式,通过ISO叉叉叉叉的认证。
23           //他们很天真地认为他们的山寨翅可以媲美麦香翅。
24           assertTrue(山寨麦香翅.equals(麦香翅)); 
25           
26           //但是结果大家都知道了,山寨翅并没有获得市场的认可,鱼目混珠终究被市场识别出来。
27           assertFalse(味道好极了.equals(市场.get(山寨麦香翅)));
28           
29           //山寨小食店苦思瞑想,终于发现了问题,原来他们指打相同的名号是不行的。
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 
    看完了不知道我想说啥?看来没认真看《Effective Java》嘛,这本书可是每个java程序员进阶必修之书,没看过真不能自称大虾级别。好了,这里说到了正题的正题,其实我想说的是:

《Effective Java》第八条:改写equals时总是要改写hashCode。


*为什么要改写hashCode
答:(书上原话)“如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类在一起正常工作,这样的集合类包括HashMap,HashSet和Hashtable.

*那么为什么会导致该类无法与所有基于散列值(hash)的集合类在一起正常工作呢?
答:且看一个HashMap的源代码解释。

HashMap是通过一个叫table[]的数组来存取,table的每个元素是一个链表结构,链表的每个元素称为 Entry<key,value>,是真正存放key和value的对象。在put的过程中,HashMap会通过特定的哈希算法将key对象的hashCode对应到table的某个索引下,然后再用key对比链表中每个Entry.key,如果key相同则更新value。否则就加入新的 Entry到链表中。

HashMap的数据结构图:




再看一段HashMap的源代码:
 1 public V put(K key, V value) {
 2     K k = maskNull(key);// 如果key为null则使用缺省的Object
 3         int hash = hash(k);//将k的hashCode经过一定的计算得到新的HashCode
 4         int i = indexFor(hash, table.length);//取得HashCode在table中的位置
 5 
 6       //首先在数组内根据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         //修改次数加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的约定(经过自己语言描述,原话自己看书去)
1.如果一个类的equals方法所用到的信息(逻辑相等的条件因素)没有被修改的话,那么它hashCode也不会改变。换个角度来看,也就是说,hashCode返回值最好与equals方法所用到的信息相关。

2.如果两个实例根据equals对比是相等的,那么它们的HashCode相等。

3.如果两个实例根据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 


程序员的一生其实可短暂了,这电脑一开一关,一天过去了,嚎;电脑一开不关,那就成服务器了,嚎……

posted on 2009-06-20 00:59 Heis 阅读(1685) 评论(0)  编辑  收藏 所属分类: Effective Java


只有注册用户登录后才能发表评论。


网站导航: