【Java基础】HashMap和Hashtable区别

HashMap和Hashtable区别

  1. hash数组初始化时机不同,Hashtable是在构造函数初始化,而HashMap是在第一次put()初始化hash数组。
  2. 在HashTable中,hash数组默认大小是11,增加的方式是old*2+1。在HashMap中,hash数组默认大小是16,增加的方式是2*old而且一定是2的整数.
  3. HashMap允许空(null)键值(key),而HashTable不允许。
  4. HashMap把Hashtable的contains()方法去掉了,改成了containsvalue()和containsKey()。
  5. Hashtable的方法是线程安全的,而HashMap不支持线程的同步,不是线程安全的。
  6. Hashtable使用Enumeration,HashMap使用Iterator。
  7. hash值的使用不同,HashTable直接使用对象的hashCode。

下面就通过源码来证明上面的7个不同。

1.hash数组初始化时机不同

//HashTable构造器 
public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);

        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
        table = new Entry[initialCapacity];//初始化Hash数组
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        initHashSeedAsNeeded(initialCapacity);
    }
//hashMap的put函数 
public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);//初始化Hash数组
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        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;
    }

2.在HashTable中,hash数组默认大小是11,增加的方式是old*2+1。在HashMap中,hash数组默认大小是16,增加的方式是2*old而且一定是2的整数.

//Hashtable构造器
public Hashtable() {
        this(11, 0.75f);//默认大小11
    }

protected void rehash() {
        int oldCapacity = table.length;
        Entry<K,V>[] oldMap = table;

        // overflow-conscious code
        int newCapacity = (oldCapacity << 1) + 1;//增加方式是2*old+1
//省略。。。。。。
}
//HashMap源码    
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 默认大小16

void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);//扩容方式是:2*old
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }

3.HashMap允许空(null)键值(key),而HashTable不允许。

这里发现Hashtable只对value为空进行了判断,却没有对key是否为空判断,然后就用hash(key)计算hash值,那么如果传入的键值为空的话,程序会报错。

//Hashtable源码 
public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();//如果值为空就抛出异常
        }
        Entry tab[] = table;
        int hash = hash(key);
//省略。。。
}
private int hash(Object k) {
        // hashSeed will be zero if alternative hashing is disabled.
        return hashSeed ^ k.hashCode();
    }
//HashMap源码 
public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
//省略。。。。。。
}
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;
    }

这里可以看出,hashmap是支持插入key为null的键值对的,而且保存在hash数组index=0位置。

4.HashMap把Hashtable的contains()方法去掉了,改成了containsvalue()和containsKey()。

hashtable的contains()方法就是判断hash数组中是否有对应的value值,所以contains()方法名字起的不好,HashMap舍弃之,并重新命名为containsvalue(),清晰明了。

//hashtable源码
 public synchronized boolean contains(Object value) {
        if (value == null) {
            throw new NullPointerException();
        }

        Entry tab[] = table;
        for (int i = tab.length ; i-- > 0 ;) {
            for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
                if (e.value.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }
//hashMap源码   
 public boolean containsValue(Object value) {
        if (value == null)
            return containsNullValue();

        Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (value.equals(e.value))
                    return true;
        return false;
    }

5.Hashtable的方法是线程安全的,而HashMap不支持线程的同步,不是线程安全的。

参考4中代码,可以看出Hashtable是加了synchronized关键字,而hashmap放弃同步来提高性能。

6.Hashtable使用Enumeration,HashMap使用Iterator。

区别这里就不说了,大家可以百度。

7.hash值的使用不同,HashTable直接使用对象的hashCode。

//hashtable的hash函数   
 private int hash(Object k) {
        // hashSeed will be zero if alternative hashing is disabled.
        return hashSeed ^ k.hashCode();
    }
//hashmap的hash函数
final int hash(Object k) {
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();

        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

hashmap的hash函数多次进行异或右移操作,目的是将hash值的高位和地位都参与运算,避免桶位聚集现象,让数据分散的更均匀一点。

  • 9
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值