JDK源码学习——HashTable和HashMap的异同

相同点:
解决哈希冲突的方法都是链地址法,定义 一个Entry类型的数组,数组中的每个元素对应着一个单链表,链表的节点存放着key-value对
不同点:
1)从继承方式来说
Hashmap继承了AbstractMap,而HashTable继承了Dictionary
2)从线程安全的角度
hashmap不是线程安全的,在并发的条件下使用hashmap的方法,需要我们手动给这些方法加上synchronized,
hashtable几乎所有的方法都已经有synchronize,所以支持多线程
3)处理NUll的方式
hashmap的key和value可以为空,如果为空会把他放到数组table[0]的位置上
hashtable的key和value不能为空,如果为空会报出NullPointerException空指针异常
4)初始容量和扩大容量的方式不同
hashmap中初始容量是2^4=16,扩容之后是原来的二倍,大小始终保持2的倍数
/**
     * Constructs a new, empty hashtable with a default initial capacity (11)
     * and load factor (0.75).
     */
    public Hashtable() {
//默认大小为11
        this(11, 0.75f);
    }


/**
     * Increases the capacity of and internally reorganizes this
     * hashtable, in order to accommodate and access its entries more
     * efficiently.  This method is called automatically when the
     * number of keys in the hashtable exceeds this hashtable's capacity
     * and load factor.
     */
    protected void rehash() {
        int oldCapacity = table.length;
        Entry<K,V>[] oldMap = table;

//容量扩大为原来的2倍加1
        // overflow-conscious code
        int newCapacity = (oldCapacity << 1) + 1;
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        Entry<K,V>[] newMap = new Entry[newCapacity];

        modCount++;
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        boolean rehash = initHashSeedAsNeeded(newCapacity);

        table = newMap;

        for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;

                if (rehash) {
                    e.hash = hash(e.key);
                }
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = newMap[index];
                newMap[index] = e;
            }
        }
    }
hashtable中默认初始容量为11,扩大容量时扩大为原来的2倍加1。
为什么要这样取?
在JDK1.7源码里面,在hashtable中计算数组下标的时候,
index = (hash & 0x7FFFFFFF) % tab.length;
没有和hashmap一样采用位运算的方法,而是采用的是直接取模的方法。hashtable会尽量使用素数或技术来作为容量的大小。当他的大小为素数的时候,直接取模的结果能够减少冲突,结果更加均匀,我们当然希望哈希结果越分散越好(证明见 http://zhaox.github.io/algorithm/2015/06/29/hash)。

猜你喜欢

转载自blog.csdn.net/shida_hu/article/details/80245606