源码分析hashmap与hashtable的区别

源码分析HashMap与HashHashTable的区别

这个题在面试中命中率极高的一个面试题,今天就和大家谈谈两者的区别有哪些。

1、继承父类不同

在这里插入图片描述
在这里插入图片描述

看源码可知:HashTable继承的父类是Dictionary(字典的意思),而HashMap继承的父类是AbstractMap类。但两者实现的接口都一样。

2、线程安全问题

HashTable是线程安全的,HashMap是线程不安全的。

HashTable类中的每个方法都给加了synchronized。虽然HashMap不是线程安全的,但是它的效率会比HashTable要好很多。如果是单线程操作的话,HashMap把这部分操作解放出来了。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。

3、key为null的处理不同

/** HashTable源码 **/


/**
     * Maps the specified <code>key</code> to the specified
     * <code>value</code> in this hashtable. Neither the key nor the
     * value can be <code>null</code>. <p>
     *
     * The value can be retrieved by calling the <code>get</code> method
     * with a key that is equal to the original key.
     *
     * @param      key     the hashtable key
     * @param      value   the value
     * @return     the previous value of the specified key in this hashtable,
     *             or <code>null</code> if it did not have one
     * @exception  NullPointerException  if the key or value is
     *               <code>null</code>
     * @see     Object#equals(Object)
     * @see     #get(Object)
     */
    public synchronized V put(K key, V value) {
    
    
        // Make sure the value is not null
        if (value == null) {
    
    
            throw new NullPointerException();
        }

HashTable的put()方法的注释中已经详细说明:当你的key或者value为null的话就会抛出空指针异常。

/** HashMap源码 **/

  /**
     * Computes key.hashCode() and spreads (XORs) higher bits of hash
     * to lower.  Because the table uses power-of-two masking, sets of
     * hashes that vary only in bits above the current mask will
     * always collide. (Among known examples are sets of Float keys
     * holding consecutive whole numbers in small tables.)  So we
     * apply a transform that spreads the impact of higher bits
     * downward. There is a tradeoff between speed, utility, and
     * quality of bit-spreading. Because many common sets of hashes
     * are already reasonably distributed (so don't benefit from
     * spreading), and because we use trees to handle large sets of
     * collisions in bins, we just XOR some shifted bits in the
     * cheapest possible way to reduce systematic lossage, as well as
     * to incorporate impact of the highest bits that would otherwise
     * never be used in index calculations because of table bounds.
     */
    static final int hash(Object key) {
    
    
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

HashMap的put()方法返回体里详细说明:当key为null,会把key值等于0进行hashcode进行计算。

4、初始容量大小不同

HashMap的初始容量是16,每一次创建一个map初始大小是往map里put值时才会开始初始容量大小。而HashTable的初始容量是11,每次new的时候就会初始这个容量。

5、扩充容量大小不同

HashMap扩充容量是原来容量的2倍,HashTable扩充容量是原来的2n+1倍。

Hashtable的侧重点是哈希结果更加均匀,使得哈希冲突减少。当哈希表的大小为素数时,简单的取模哈希的结果会更加均匀。而HashMap则更加关注hash的计算效率问题。在取模计算时,如果模数是2的幂,那么我们可以直接使用位运算来得到结果,效率要大大高于做除法。HashMap为了加快hash的速度,将哈希表的大小固定为了2的幂。当然这引入了哈希分布不均匀的问题,所以HashMap为解决这问题,又对hash算法做了一些改动。这从而导致了Hashtable和HashMap的计算hash值的方法不同。

6、计算hash值的方法也不同

/** HashTable源码 **/

在这里插入图片描述

Hashtable直接使用对象自身的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。hash & 0x7FFFFFFF 是将哈希值变为正数,然后再使用除留余数发来获得最终的位置并映射到哈希表中。Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。

/** HashMap源码 **/

在这里插入图片描述

‘>>>’是无符号右移操作,高位补0.

首先判断key是不是等于null,等于null,则返回0作为哈希值。否则,运算(h=key.hashCode()) ^ (h >>> 16),将key的哈希值的高位与低位异或的结果作为低位,改为不变。

首先判断key是不是等于null,等于null,则返回0作为哈希值。否则,运算(h=key.hashCode()) ^ (h >>> 16),将key的哈希值的高位与低位异或的结果作为低位,改为不变。

猜你喜欢

转载自blog.csdn.net/weixin_47294072/article/details/107550919