HashMap,HashTable比较

HashTable操作

HashTable的操作几乎和HashMap一致,主要的区别在于HashTable为了实现多线程安全,在几乎所有的方法上都加上了synchronized锁,而加锁的结果就是HashTable操作的效率十分低下

HashTable与HashMap对比

(1)线程安全:HashMap是线程不安全的类,多线程下会造成并发冲突,但单线程下运行效率较高;HashTable是线程安全的类,很多方法都是用synchronized修饰,但同时因为加锁导致并发效率低下,单线程环境效率也十分低;

(2)插入null:HashMap允许有一个键为null,允许多个值为null;但HashTable不允许键或值为null

(3)容量:HashMap底层数组长度必须为2的幂,这样做是为了hash准备,默认为16;扩容为2倍

       而HashTable底层数组长度可以为任意值,这就造成了hash算法散射不均匀,容易造成hash冲突,默认为11;扩容为2n+1

         扩容详见:扩容机制

(4)Hash映射:HashMap的hash算法通过非常规设计,将底层table长度设计为2的幂,使用位与运算代替取模运算,减少运算消耗;而HashTable的hash算法首先使得hash值小于整型数最大值,再通过取模进行散射运算;

(5)扩容机制HashMap创建一个为原先2倍的数组,然后对原数组进行遍历以及rehash;HashTable扩容将创建一个原长度2倍的数组,再使用头插法将链表进行反序;

  • capacity 即容量,默认16
  • loadFactor 加载因子,默认是0.75
  • threshold 阈值。阈值=容量*加载因子。默认12。当元素数量超过阈值时便会触发扩容

    HashMap的容量变化通常存在以下几种情况:

    1. 空参数的构造函数:实例化的HashMap默认内部数组是null,即没有实例化。第一次调用put方法时,则会开始第一次初始化扩容,长度为16。
    2. 有参构造函数:用于指定容量。会根据指定的正整数找到不小于指定容量的2的幂数,将这个数设置赋值给阈值(threshold)。第一次调用put方法时,会将阈值赋值给容量,然后让 [公式] 。(因此并不是我们手动指定了容量就一定不会触发扩容,超过阈值后一样会扩容!!)
    3. 如果不是第一次扩容,则容量变为原来的2倍,阈值也变为原来的2倍。(容量和阈值都变为原来的2倍时,负载因子还是不变)

    此外还有几个细节需要注意:

    • 首次put时,先会触发扩容(算是初始化),然后存入数据,然后判断是否需要扩容;
    • 不是首次put,则不再初始化,直接存入数据,然后判断是否需要扩容;

 

(6)结构区别:HashMap是由数组+链表形成,在JDK1.8之后链表长度大于8时转化为红黑树;而HashTable一直都是数组+链表;

(7)继承关系:HashTable继承自Dictionary类;而HashMap继承自AbstractMap类;

(8)迭代器:HashMap是fail-fast,而HashTable不是。

posted @ 2021-12-07 11:37  YanSss  阅读(75)  评论(0编辑  收藏  举报