HashMap底层原理

哈希表:在哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1).

数据结构的物理存储结构只有两种:顺序存储结构和链式存储结构(像栈,队列,树,图等是从逻辑结构去抽象的,映射到内存中,也这两种物理组织形式),而在上面我们提到过,在数组中根据下标查找某个元素,一次定位就可以达到,哈希表利用了这种特性,哈希表的主干就是数组。

HashMap底层是由数组和链表两种数据结构组合而成的,采用这种数据结果既能方便地读取数据,又可以方便地进行增加和删除的操作。

如果要新增或查找某个元素,我们通过把当前元素的关键字 通过哈希函数映射到数组中的某个位置,通过数组下标一次定位就可完成操作。

存储位置 = f(关键字)

Key.hashcode,该方法会返回一个32位的int类型的值,以int h = key.hashCode()为例。获取到h的值之后,会计算该key对应的哈希表中的数组的位置,计算方法就是取模运算,h%table.length。因为table的长度为2的整数次幂,所以可以用h与table.length-1直接进行位与运算。

index = h &(table.length-1)。得到的index就是放置新数据的位置。

哈希冲突:

如果两个不同的元素,通过哈希函数得出的实际存储地址相同,也就是说,当对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,出现哈希冲突。哈希函数的设计至关重要,好的哈希数会尽可能地保证 计算简单和散列地址分布均匀。

数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突。那么哈希冲突的解决方案有多种:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式。

实现原理

HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。

HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,仅需简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

扩容机制

HashMap内存储数据的Entry数组默认是16,如果没有对Entry扩容机制的话,当存储的数据一多,Entry内部的链表会很长,这就失去了HashMap的存储意义了。所以HasnMap内部有自己的扩容机制。HashMap内部有:

变量size,它记录HashMap的底层数组中已用槽的数量;

变量threshold,它是HashMap的阈值,用于判断是否需要调整HashMap的容量(threshold = 容量*加载因子)

变量DEFAULT_LOAD_FACTOR = 0.75f,默认加载因子为0.75

HashMap扩容的条件是:当size大于threshold时,对HashMap进行扩容。

扩容是是新建了一个HashMap的底层数组,而后调用transfer方法,将就HashMap的全部元素添加到新的HashMap中(要重新计算元素在新的数组中的索引位置)。 很明显,扩容是一个相当耗时的操作,因为它需要重新计算这些元素在新的数组中的位置并进行复制处理。因此,我们在用HashMap的时,最好能提前预估下HashMap中元素的个数,这样有助于提高HashMap的性能。

HashMap共有四个构造方法。构造方法中提到了两个很重要的参数:初始容量和加载因子。这两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中槽的数量(即哈希数组的长度),初始容量是创建哈希表时的容量(从构造函数中可以看出,如果不指明,则默认为16),加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 resize 操作(即扩容)。

加载因子,如果加载因子越大,对空间的利用更充分,但是查找效率会降低(链表长度会越来越长);如果加载因子太小,那么表中的数据将过于稀疏(很多空间还没用,就开始扩容了),对空间造成严重浪费。

系统默认加载因子为0.75,这是一个比较理想的值,一般情况下我们是无需修改的。

构造方法都会将实际容量设为不小于指定容量的2的次方的一个数,且最大值不能超过2的30次方。

HashTable

与hashmap的区别:

· HashMap是非同步的,没有对读写等操作进行锁保护,所以是线程不安全的,在多线程场景下会出现数据不一致的问题。而HashTable是同步的,所有的读写等操作都进行了锁(synchronized)保护,在多线程环境下没有安全问题。但是锁保护也是有代价的,会对读写的效率产生较大影响。

· HashMap结构中,是允许保存null的,Entry.key和Entry.value均可以为null。但是HashTable中是不允许保存null的。

· HashMap的迭代器(Iterator)是fail-fast迭代器,但是Hashtable的迭代器(enumerator)不是fail-fast的。如果有其它线程对HashMap进行的添加/删除元素,将会抛出ConcurrentModificationException,但迭代器本身的remove方法移除元素则不会抛出异常。这条同样也是Enumeration和Iterator的区别。

hashmap原理_HashMap和HashTable底层原理以及区别相关推荐

  1. java hashtable 数据结构_java Hashtable底层原理是怎样的?数据结构包括什么?

    大家都知道,随着近些年科学技术水平的不断进步与发展,学习编程语言的人也越来越多了.很多人对于java中的一些常见知识点有些不了解,今天就来为大家详细介绍一下. 首先说一下具体的概念: HashTabl ...

  2. ipc原理linux,Docker 的底层原理,了解它只需要 5分钟!

    作者:小姐姐养的狗 来源:高效运维 一位同学曾给我打比方:宿主机就好比一间大房子,docker 把它变成了N个小隔断.在这些小隔断之间,有独立的卫生间.小床.电视- 麻雀虽小,五脏俱全,这个比喻非常的 ...

  3. java arraylist底层实现原理_ArrayList和LinkedList底层原理

    ArrayList和LinkedList都是List的实现类,是在日常开发中经常被使用到的两个集合,我们来结合源码看下两个集合的不同之处. 先来看下ArrayList的源码: // 默认的初始化大小p ...

  4. java Map及其实现类的底层原理

    文章目录 一.Map接口及其多个实现类的对比 二.Map中存储的key-value特点 三.HashMap在JDK7中的底层原理 四.HashMap在JDK8中的底层原理 五.HashMap在JDK7 ...

  5. Java集合框架底层原理

    Java集合框架 Java集合框架 List集合 ArrayList底层实现原理 ArrayList数组扩容技术(数组拷贝) 扩容大小 查询和删除 集合中的泛型 LinkedList Vector 线 ...

  6. synchronized原理_面试必备—Synchronized 关键字使用、底层原理

    在并发编程中存在线程安全问题,主要原因有: 1.存在共享数据 2.多线程共同操作共享数据 关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchro ...

  7. CAS基础及底层原理

    目录 一.CAS基本概念及运用 二.CAS底层原理1 三.CAS底层原理2 四.CAS的缺点 一.CAS基本概念及运用 CAS表层意思就是compareAndSet即比较并交换 CAS的全称为Comp ...

  8. hashMap和hashTable的区别以及HashMap的底层原理?

    hashMap和hashTable的区别? 1.继承的父类不同 HashTable继承Dictionary类,而hashMap继承了AbstractMap类,但是二者都实现了map接口. 2.线程安全 ...

  9. HashMap 的底层原理

    HashMap 的底层原理 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端. 数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二 ...

最新文章

  1. 傅里叶变换拉普拉斯变换的物理解释及区别
  2. 制作模板_木模板制作流程
  3. 骰子的妙用---课堂答题
  4. SSM查看详情功能逻辑代码以及关联码表显示
  5. Shell--cut用法
  6. asp.net(c#)将彩色图片变灰阶图片
  7. Django从理论到实战(part7)--关于视图函数与URL映射
  8. mysql 5.7 mts_mysql5.7 中启用MTS后error log中大量Note日志分析
  9. 神奇的applycall
  10. Mysql通过一个限制条件,查出多条不同的记录
  11. iOS 操作系统被曝无线网络命名bug 导致 iPhone无法连接无线网络
  12. SV fork-join
  13. Java 编程(基础面试题)
  14. VirtualBox 中的Centos如何安装VBoxGuestAdditions
  15. 鉴源实验室丨汽车网络安全需求分析方法综述
  16. 如何让微信号开通检测软件替你顶起一片天?
  17. Python验证信用卡号的有效性(算法)(称为Luhn检测或者mod 10 检测)
  18. 元素选择器(type selectors)
  19. nginx 在海思平台移植编译
  20. ResNet残差网络Pytorch实现——对花的种类进行训练

热门文章

  1. K12,再好的愿景遇到商业都会慢慢失去真正的目标
  2. Eclipse下svn的创建分支/合并/切换使用
  3. 关于SQL命令中不等号(!=,)
  4. Ibatis调用Oracle存储过程,以及返回Cursor结果集的问题
  5. 怎样使一个Android应用不被杀死?
  6. Scrum看板工具Leangoo记录我的装修事件,hhhh
  7. 计算机网络原理超详解说
  8. Java并发必知必会第三弹:用积木讲解ABA原理
  9. 什么?Redis 的 QPS 是 MySQL 的 100 倍?
  10. 你还在为怎么查看字节码指令而担忧吗?