HashMap和Hashtable的區別

HashMap和Hashtable的區別 算法

一、Hashtable是基於陳舊的Dictionary類,完成了Map接口;HashMap是Java1.2引進的map的基於散列表的實現,取代了HashTable(HashMap繼承AbstractMap完成Map接口); 數組

二、HashTable是同步的,線程安全的一個Collection,HashMap是未同步,因此在多線程場合要手動同步HashMap。 安全

三、HashTable不容許null值(key和value都不能夠),HashMap容許,即HashTable不容許null值其實在編譯期不會有任何的不同,會照樣執行,在運行時hashtable中設置空值會出現空指針異常。HashMap能夠用containsKey來判斷是否有該鍵。 多線程

四、HashTable使用Enumeration,HashMap使用Iterator。 框架

五、HashTable中hash數組默認大小是11,增長方式是old*2+1.HashMap中hash數組的默認大小是16,並且必定是2的指數。 性能

六、Hash值的使用不一樣,HashTable直接使用對象的hashCode spa

int hash = key.hashCode(); 線程

int index = (hash & 0x7FFFFFFF)%tab.length; 指針

而 HashMap從新計算hash值,並且用於代替求模: 對象

int hash = hash(k);

int i = indexFor(hash, table.length);

static int hash(Object x){

int h = x.hashCode();

h+=~(h<<9);

h^=(h>>>14);

h+=(h<<4);

h^=(h>>>10);

return h;

}

static int indexFor(int h, int length)

{

return h&(length-1);

}

區別

Hashtable

Hashmap

繼承、實現

Hashtable extends Dictionary implements Map, Cloneable,Serializable

HashMap extends AbstractMap implements Map, Cloneable,Serializable

線程同步

已經同步過的能夠安全使用

未同步的,可使用Colletcions進行同步Map Collections.synchronizedMap(Map m)

對null的處理


Hashtable table = new Hashtable();

table.put(null, "Null");

table.put("Null", null);

table.contains(null);

table.containsKey(null);

table.containsValue(null);

後面的5句話在編譯的時候不會有異常,可在運行的時候會報空指針異常具體緣由能夠查看源代碼

public synchronized V put(K key, V value) {

// Make sure the value is not null

if (value == null) {

throw new NullPointerException();

}

HashMap map = new HashMap();
map.put(null, "Null");

map.put("Null", null);

map.containsKey(null);

map.containsValue(null);

以上這5條語句不管在編譯期,仍是在運行期都是沒有錯誤的.

在HashMap中,null能夠做爲鍵,這樣的鍵只有一個;能夠有一個或多個鍵所對應的值爲null。當get()方法返回null值時,便可以表示 HashMap中沒有該鍵,也能夠表示該鍵所對應的值爲null。所以,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵,而應該用containsKey()方法來判斷。

增加率

protected void rehash() {

int oldCapacity = table.length;

Entry[] oldMap = table;

int newCapacity = oldCapacity * 2 + 1;

Entry[] newMap = new Entry[newCapacity];

modCount++;

threshold = (int)(newCapacity * loadFactor);

table = newMap;

for (int i = oldCapacity ; i-- > 0 ;) {

for (Entry old = oldMap[i] ; old != null ; ) {

Entry e = old;

old = old.next;

int index = (e.hash & 0x7FFFFFFF) % newCapacity;

e.next = newMap[index];

newMap[index] = e;

}

}

}


void addEntry(int hash, K key, V value, int bucketIndex) {

Entry e = table[bucketIndex];

table[bucketIndex] = new Entry(hash, key, value, e);

if (size++ >= threshold)

resize(2 * table.length);

}


哈希值的使用

HashTable直接使用對象的hashCode,代碼是這樣的:

public synchronized boolean containsKey(Object key) {

Entry tab[] = table;

int hash = key.hashCode();

int index = (hash & 0x7FFFFFFF) % tab.length;

for (Entry e = tab[index] ; e !=null ; e = e.next) {

if ((e.hash == hash) && e.key.equals(key)) {

return true;

}

}

return false;

}

HashMap從新計算hash值,並且用與代替求模

public boolean containsKey(Object key) {

Object k = maskNull(key);

int hash = hash(k.hashCode());

int i = indexFor(hash, table.length);

Entry e = table[i];

while (e != null) {

if (e.hash == hash && eq(k, e.key))

return true;

e = e.next;

}

return false;

}



TreeMap是基於紅黑樹實現的。查看「鍵」時會被排序,次序由(Comparable或Comparator決定)。

hashtable和HashMap採用的hash/rehash算法都大概同樣,因此性能不會有很大的差別。

public static void main(String args[])
{
HashTable h=new HashTable();
h.put("用戶1",new Integer(90));
h.put("用戶2",new Integer(50));
h.put("用戶3",new Integer(60));
h.put("用戶4",new Integer(70));
h.put("用戶5",new Integer(80));
Enumeration e=h.elements();
while(e.hasMoreElements()){
System.out.println(e.nextElement());
}


map 的方法:clear()從 Map 中刪除全部映射

remove(Object key)從 Map 中刪除鍵和關聯的值

 put(Object key, Object value)將指定值與指定鍵相關聯 

get(Object key)返回與指定鍵關聯的值

containsKey(Object key)若是 Map 包含指定鍵的映射,則返回 true 

containsValue(Object value)若是此 Map 將一個或多個鍵映射到指定值,則返回 true

isEmpty()若是 Map 不包含鍵-值映射,則返回 true size()返回 Map 中的鍵-值映射的數目


List 接口對Collection進行了簡單的擴充,它的具體實現類經常使用的有ArrayList和LinkedList。你能夠將任何東西放到一個List容器中,並在須要時從中取出。ArrayList從其命名中能夠看出它是一種相似數組的形式進行存儲,所以它的隨機訪問速度極快,而LinkedList的內部實現是鏈表,它適合於在鏈表中間須要頻繁進行插入和刪除操做。在具體應用時能夠根據須要自由選擇。前面說的Iterator只能對容器進行向前遍歷,而 ListIterator則繼承了Iterator的思想,並提供了對List進行雙向遍歷的方法。 

Set接口也是 Collection的一種擴展,而與List不一樣的是,在Set中的對象元素不能重複,也就是說你不能把一樣的東西兩次放入同一個Set容器中。它的經常使用具體實現有HashSet和TreeSet類。HashSet能快速定位一個元素,可是你放到HashSet中的對象須要實現hashCode()方法,它使用了前面說過的哈希碼的算法。而TreeSet則將放入其中的元素按序存放,這就要求你放入其中的對象是可排序的,這就用到了集合框架提供的另外兩個實用類Comparable和Comparator。一個類是可排序的,它就應該實現Comparable接口。有時多個類具備相同的排序算法,那就不須要在每分別重複定義相同的排序算法,只要實現Comparator接口便可。集合框架中還有兩個很實用的用類:Collections和 Arrays。Collections提供了對一個Collection容器進行諸如排序、複製、查找和填充等一些很是有用的方法,Arrays則是對一個數組進行相似的操做。 

 Map是一種把鍵對象和值對象進行關聯的容器,而一個值對象又能夠是一個Map,依次類推,這樣就可造成一個多級映射。對於鍵對象來講,像Set同樣,一個Map容器中的鍵對象不容許重複,這是爲了保持查找結果的一致性;若是有兩個鍵對象同樣,那你想獲得那個鍵對象所對應的值對象時就有問題了,可能你獲得的並非你想的那個值對象,結果會形成混亂,因此鍵的惟一性很重要,也是符合集合的性質的。固然在使用過程當中,某個鍵所對應的值對象可能會發生變化,這時會按照最後一次修改的值對象與鍵對應。對於值對象則沒有惟一性的要求。你能夠將任意多個鍵都映射到一個值對象上,這不會發生任何問題(不過對你的使用卻可能會形成不便,你不知道你獲得的究竟是那一個鍵所對應的值對象)。Map有兩種比較經常使用的實現: HashMap和TreeMap。HashMap也用到了哈希碼的算法,以便快速查找一個鍵,TreeMap則是對鍵按序存放,所以它便有一些擴展的方法,好比firstKey(),lastKey()等,你還能夠從TreeMap中指定一個範圍以取得其子Map。鍵和值的關聯很簡單,用put (Object key,Object value)方法便可將一個鍵與一個值對象相關聯。用get(Object key)可獲得與此key對象所對應的值對象。
相關文章
相關標籤/搜索