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.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 包含指定鍵的映射,則返回 truecontainsValue(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對象所對應的值對象。