HashMap VS Hashtable

HashMap和Hashtable都位于java.util包中,实现机制基本差不多,现在一般建议使用HashMap,但也有一些区别,主要是对于null键值的处理。

它们都是基于hash原则,何为hashcode?简单说就是对变量/对象的属性应用某种算法后得到的一个唯一的串,用这个串来确定变量/对象的唯一性,一般多是在内存中的地址。都处理为一个数组,数组中都是存放的Entry链表,Entry(int hash, K key, V value, Entry<K,V> next),都是针对(key,value)的键值对处理,如果key一致,新值覆盖旧值。

    区别如下:

1.Hashtable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap

2.初始默认数组大小不一样,HashMap为16(MUST be a power of two,Hashtable为11,自动扩容方式为oldCapacity * 2 + 1;

3.Hashtable用的是Enumeration,旧框架的缘故,HashMap为Iterator;

4.Hashtable不允许键值为null的情况,HashMap允许(key,value为null均可以),主要操作就是put和get。

  HashMap的put方法:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }


首先判断key是否为空,为空则放入数据的table[0]位置,因为null的hashcode为0;

 private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }

key不为空,则根据hashcode算出新的hash(防止开发人员重写hashcode()方法,导致hashcode值过大过小等情况),然后算出在table数组的具体位置,遍历此table[i]链表,如果hash一样,key一致,新值覆盖旧值并返回旧值,否则在table[i]的链表头部新增一个Entry。

而Hashtable的put方法:

public synchronized V put(K key, V value) {
	// Make sure the value is not null
	if (value == null) {
	    throw new NullPointerException();
	}

	// Makes sure the key is not already in the hashtable.
	Entry tab[] = table;
	int hash = key.hashCode();
	int index = (hash & 0x7FFFFFFF) % tab.length;
	for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
	    if ((e.hash == hash) && e.key.equals(key)) {
		V old = e.value;
		e.value = value;
		return old;
	    }
	}

	modCount++;
	if (count >= threshold) {
	    // Rehash the table if the threshold is exceeded
	    rehash();

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

	// Creates the new entry.
	Entry<K,V> e = tab[index];
	tab[index] = new Entry<K,V>(hash, key, value, e);
	count++;
	return null;
    }

此处如果value为null,则抛出异常,Hashtable中的hashcode并未经过任何算法加工,直接用的就是key的hashcode,然后根据(hash & 0x7FFFFFFF) % tab.length算出在数组中的具体位置,并将值放入。

HashMap的get()方法:

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

如果已经了解HashMap的put()方法就很容易理解了。

Hashtable的get()方法:

public synchronized V get(Object key) {
	Entry tab[] = table;
	int hash = key.hashCode();
	int index = (hash & 0x7FFFFFFF) % tab.length;
	for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
	    if ((e.hash == hash) && e.key.equals(key)) {
		return e.value;
	    }
	}
	return null;
    }


理解也不难。

其他也有些方法的差别,你有我无,你无我有等等。


你可能感兴趣的:(HashMap VS Hashtable)