自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Hashtable和HashMap引發(fā)的血案

開發(fā) 后端
本票文章很生動的給Hashtable和HashMap舉例,并給出代碼,方便大家理解。

人物:

王小胖:性別:男。程序員,工作經(jīng)驗1 year。愛好:吃肉、電玩、馬小花。特技:吃肉不用考慮胃的容量。

馬小花:性別:女。學生,工作經(jīng)驗0 year。愛好:蛋糕、臭美、王小胖。特技:能夠降服王小胖……

/**2011年2月,電影《將愛情進行到底》火得不得了。周末,小胖也陪著小花去看這部電影。放映中,小花被影片中的靖哥哥和杜拉拉感動的一沓糊涂,而小胖則心里暗自后悔沒有買一袋大爆米花來打發(fā)這無聊的時間。影片結束,小花已經(jīng)是鼻涕一把淚一把,小胖也只有裝模作樣地抽動了幾下鼻子,一心只想著一會兒是吃麥當勞還是必勝客。*/

回到家中,小胖和小花各自玩著電腦。

小花:胖子,你知道Hashtable和HashMap的區(qū)別嗎?

小胖:略知。

小花:……裝什么!!給我講講!!!

小胖:好的……

第一個區(qū)別就先來說說繼承關系吧。

如果你在baidu里google一下(技術類文章的搜索還是推薦google),會發(fā)現(xiàn)網(wǎng)上的大致說法與“由于Java發(fā)展的歷史原因。Hashtable是基于陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現(xiàn)。”相同。這種說法沒有錯,但是胖子覺得不夠準確,特別是對于我們這種大眾菜鳥來說,如果不去深究的話,可能就會造成一些理解上的差異。簡單的認為Hashtable沒有繼承Map接口。胖子之前就犯過這樣的錯誤(胖子承認自己笨,是真笨……)。

小花:那你怎么知道它們兩個各自的繼承關系呢?胖子。

我們可以參考一下最新的JDK1.6的源碼,看看這兩個類的定義:

Java代碼

 

  1. public class Hashtable     
  2.     extends Dictionary     
  3. implements Map, Cloneable, java.io.Serializable {…}     
  4.       
  5. public class HashMap     
  6.     extends AbstractMap     
  7. implements Map, Cloneable, Serializable {…}   

可以看到hashtable也是繼承了Map接口。它們的不同是Hashtable(since JDK1.0)就繼承了Dictionary這個抽象類,而HashMap(since JDK1.2)繼承的則是AbstractMap這個抽象類。因為在Hashtable中看到繼承Map后所實現(xiàn)的方法是JDK1.2版本時加上去的,所以胖子猜想可能是在JDK 1.2開發(fā)時Sun工程師出于統(tǒng)一的考慮使得Hashtable也繼承了Map接口。

小花:哦,原來JDK源碼還能看出來這個。

小胖:……后面還能看出更多東西的。

小花:好期待啊。

第二個區(qū)別我們從同步和并發(fā)性上來說說它們兩個的不同。

可以通過這兩個類得源碼來分析,Hashtable中的主要方法都做了同步處理,而HashMap則沒有??梢哉fHashtable在默認情況支持同步,而HashMap在默認情況下是不支持的。我們在多線程并發(fā)的環(huán)境下,可以直接使用Hashtable,但是要使用HashMap的話就要自己增加同步處理了。對HashMap的同步處理可以使用Collections類提供的synchronizedMap靜態(tài)方法;或者直接使用JDK5.0之后提供的java.util.concurrent包里的ConcurrentHashMap類。

小胖:synchronizedMap靜態(tài)方法和ConcurrentHashMap類我會以后再給你詳細講一下的。肥婆。

小花:你保證啊。鑰匙忘了你知道后果的。

小胖:好的……

第三個區(qū)別就是它們對于null值的處理方式了。

我們依然能夠從源代碼中得知,Hashtable中,key和value都不允許出現(xiàn)null值。

Java代碼

 

  1. public synchronized V put(K key, V value) {     
  2.    // Make sure the value is not null     
  3.    if (value == null) {     
  4.        throw new NullPointerException();     
  5.    }     
  6.       
  7.    // Makes sure the key is not already in the hashtable.     
  8.    Entry tab[] = table;     
  9.    int hash = key.hashCode();     
  10.    int index = (hash & 0x7FFFFFFF) % tab.length;     
  11.    //…     
  12. }   

在我們使用上面的方法時,如參數(shù)value為null,可以從代碼中直接看出程序會拋出NullPointerException;而在key為null時,則會在“int hash = key.hashCode();“這段計算Hash值的過程中拋出NullPointerException。而在在HashMap中,允許null作為key存在,并且和其他key的特性一樣,這樣的null值key只能有一個;另外HashMap允許多個value為null。這樣大家就要注意了, HashMap中就不能用get(key)方法來判斷HashMap中是否存在某個key,因為value為null和不存在該key的Entry都會返回null值,而應該用containsKey()方法來判斷了。

Java代碼

 

  1. import java.util.HashMap;     
  2. import java.util.Map;     
  3. import java.util.Map.Entry;     
  4.       
  5. public class TestCase {     
  6.       
  7.     public static void main(String[] args) {     
  8.        Map hashMap = new HashMap();     
  9.        hashMap.put(0null);     
  10.        hashMap.put(1"one");     
  11.        hashMap.put(2"two");     
  12.        hashMap.put(null"null");     
  13.        for(Entry e : hashMap.entrySet()) {     
  14.            System.out.println("Key: " + e.getKey() + " -- Value: " + e.getValue());     
  15.        }     
  16.        System.out.println(hashMap.get(0));     
  17.        System.out.println(hashMap.get(4));     
  18.        System.out.println("Contains key 0 ? :" + hashMap.containsKey(0));     
  19.        System.out.println("Contains key 4 ? :" + hashMap.containsKey(4));     
  20.        System.out.println("Contains value null ? :" + hashMap.containsValue(null));     
  21.     }     
  22.       
  23. }  

結果:

Java代碼

 

  1. Key: null -- Value: null    
  2. Key: 0 -- Value: null    
  3. Key: 1 -- Value: one     
  4. Key: 2 -- Value: two     
  5. null    
  6. null    
  7. Contains key 0 ? :true    
  8. Contains key 4 ? :false    
  9. Contains value null ? :true   

HashMap對于null值key的處理網(wǎng)上有說“null 用new Object()來代替,其Entry.hashCode=0,而且在取出的時候還會還回null的?!迸肿游以谧x取源碼的過程中看到了null值的hash值確實是0 (內(nèi)部實現(xiàn)的數(shù)組中的index也是),但是能力有限沒有看到轉為new Object()的過程。

小花: 原來hashMap的containsKey還有這么個陷阱,以后肥婆要小心了。

第四個不同就是它們兩個Hash值的獲取方式了。

還是通過源代碼源代碼,Hashtable是直接使用key對象的hash值。

Java代碼

 

  1. public synchronized V put(K key, V value) {     
  2.        // Make sure the value is not null     
  3.        if (value == null) {     
  4.            throw new NullPointerException();     
  5.        }     
  6.       
  7.        // Makes sure the key is not already in the hashtable.     
  8.        Entry tab[] = table;     
  9.        int hash = key.hashCode();//hashcode     
  10.        int index = (hash & 0x7FFFFFFF) % tab.length;     
  11.        //…     
  12. }   

而HashMap則是利用key對象的hash值重新計算一個新的hash值。

Java代碼

 

  1. public V put(K key, V value) {     
  2.         if (key == null)     
  3.             return putForNullKey(value);     
  4.         int hash = hash(key.hashCode());//hashcode     
  5.         int i = indexFor(hash, table.length);     
  6.         //…     
  7. }     
  8.       
  9. static int hash(int h) {     
  10.         h ^= (h >>> 20) ^ (h >>> 12);     
  11.         return h ^ (h >>> 7) ^ (h >>> 4);     
  12.     }  

小花:胖子,都用了hash算法,你給我講講Hash算法吧。

小胖:嗯……以后的,今天我比較忙(其實是不會)。

小花:你是不是不會啊?嘿嘿(壞笑)。

小胖:什么不會……談下一話題……

第五個不同就是Hashtable和HashMap它們兩個內(nèi)部實現(xiàn)方式的數(shù)組的初始大小和擴容的方式。

HashMap中內(nèi)部數(shù)組的初始容量是16, 加載因子為0.75,而且數(shù)組容量增容后也要是2指數(shù)次冪:

Java代碼

 

  1. /**    
  2.      * The default initial capacity - MUST be a power of two.    
  3.      */    
  4. static final int DEFAULT_INITIAL_CAPACITY = 16;     
  5. /**    
  6.      * The load factor used when none specified in constructor.    
  7.      */    
  8.     static final float DEFAULT_LOAD_FACTOR = 0.75f; 

HashTable中的內(nèi)部數(shù)組的初始容量是11,加載因子也是0.75數(shù)組的增容方式為(oldCapacity * 2 + 1):

Java代碼

 

  1. public Hashtable() {     
  2.        this(110.75f);     
  3.  }     
  4.       
  5. protected void rehash() {     
  6.        int oldCapacity = table.length;     
  7.        Entry[] oldMap = table;     
  8.       
  9.        int newCapacity = oldCapacity * 2 + 1;     
  10.        //…     
  11. }   

第六個不同我們從它們兩個遍歷方式的內(nèi)部實現(xiàn)上來說。

Hashtable HashMap都使用了 Iterator。而由于歷史原因,Hashtable還使用了Enumeration的方式 。

小花:Iterator和Enumeration的區(qū)別是什么啊?給我講講。

小胖:我不是說我沒有時間嘛,下回的。

小花:我都記下來,省得你給我混過去。(拿起筆開始記賬中)

小胖:……(緊張)

第七個不同時它們的拷貝構造函數(shù)的不同。

依然是通過查看源碼,可以發(fā)現(xiàn)它們兩個對于拷貝函數(shù)初始容量的不同值。

HashMap的實現(xiàn)是:

Java代碼

 

  1. public HashMap(Mapextends K, ? extends V> m) {     
  2.         this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,     
  3.                       DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);     
  4.         putAllForCreate(m);     
  5.     }   

而Hashtable的實現(xiàn)是:

Java代碼

 

  1. public Hashtable(Mapextends K, ? extends V> t) {     
  2.        this(Math.max(2*t.size(), 11), 0.75f);     
  3.        putAll(t);     
  4.     }   

小胖:今天講的已經(jīng)很多了。我有點餓了,肥婆。

小花:看你今天的表現(xiàn)這么好。走,帶你去吃烤肉去。

小胖:哈哈,肥婆萬歲。

PS:下面打算寫的一些東西

TreeMap的排序及其他相關集合類

synchronizedMap的使用方式

concurrentMap實現(xiàn)細節(jié)和使用

Properties使用說明和 擴展

Iterator和Enumeration的區(qū)別

Hash算法 的實現(xiàn)

【編輯推薦】

  1. 透過Java中的HashMap了解Map接口
  2. Java中對HashMap的深度分析
  3. Java中對HashMap的深度分析與比較
  4. 深入探究J2ME Hashtable實現(xiàn)原理
  5. java的hashtable的用法
責任編輯:金賀 來源: JavaEye博客
相關推薦

2021-01-11 05:30:04

Boot 單機片

2015-02-04 14:36:07

格式串漏洞Ghost漏洞安全漏洞

2017-03-20 19:40:29

AndroidSwipeRefres下拉刷新

2021-07-27 07:12:11

Getter接口Setter

2023-01-11 08:41:47

微服務循環(huán)依賴

2022-04-12 08:43:04

生產(chǎn)故障Dubbo調(diào)用

2021-12-01 06:59:27

架構

2019-09-09 08:30:57

MYSQL代碼數(shù)據(jù)庫

2018-11-22 15:50:27

MySQL數(shù)據(jù)庫雙引號

2021-01-25 08:08:22

APP機器人KOB

2024-09-04 15:17:23

2020-01-06 09:43:14

賠償TSB遷移

2021-02-01 10:42:47

MySQL雙引號數(shù)據(jù)庫

2017-05-22 08:35:07

MySQL雙引號錯位

2013-08-26 10:19:24

納斯達克數(shù)據(jù)專線交易暫停

2017-08-25 16:38:05

表達式正則血案

2016-12-01 09:30:03

運維網(wǎng)絡網(wǎng)線

2013-03-18 09:56:18

2022-06-14 08:00:28

切換包管理器版本

2011-05-20 12:34:05

大話IT云服務中斷亞馬遜
點贊
收藏

51CTO技術棧公眾號