背景:

今天早上同事在研究HashMap,我凑过去说hashMap 我了解前两天刚看的(有点贱贱😄😄),我可以给你讲讲。同事就说那讲讲呗。然后我就充满信心的拿着笔边说边画:HaspMap是数组和链表的组合,jdk8中HashMap的默认长度是16,是根据key值hash出index值。当hash值出现重复时就会在index中创建链表;

Java map 的默认长度 java map最大长度_内存结构

讲到这是同事提出了夺命3问

  • 链表是什么?(“呃,以前学过现在好像不记得了”)
  • HashMap和其他map有什么区别,它有什么好处对比别的map?(“这个,这个,可能是因为只存了hashCode值”)
  • 那如果有相同的hashCode值,怎么找到这个值哪?(“这个应该是先找到根据hashkey值找对应的index,然后。。。。。”)
    以上三问后面的括号是我的回答,当时着实尴尬,本来还是去给人家讲,结果被问到了。明明前两天看了Hashmap的一些文章。只是简单的了解一下它的数据结构。今天接着上午的尴尬,晚上总结一下省的以后再遇见这种事,下面正式进入主题。

1.链表

链表 :链表是由一组不必相连(不必相连:可以连续也可以不连续)的内存结构 【节点】,按特定的顺序连接在一起的抽象数据类型。

链表常用的有 3 类: 单链表、双向链表、循环链表。

单链表:由各个内存结构通过一个 Next 指针链接在一起组成,每一个内存结构都存在后继内存结构【链尾除外】,内存结构由数据域和 Next 指针域组成。

Java map 的默认长度 java map最大长度_Java map 的默认长度_02


双向链表:由各个内存结构通过指针 Next 和指针 Prev 链接在一起组成,每一个内存结构都存在前驱内存结构和后继内存结构【链头没有前驱,链尾没有后继】,内存结构由数据域、Prev 指针域和 Next 指针域组成。

Java map 的默认长度 java map最大长度_数据结构_03

2.HashMap的简介

HashMap是基于哈希表的Map实现的,一个Key对应一个Value,允许使用null键和null值,不保证映射的顺序,映射顺序根据map的大小是发生改变的。
加粗样式

  • 什么是哈希表?

哈希表和数组,链表结构类型,就是通过下标一次性找到想要的数据。例如:如果我们想要找到表的中某个元素,需要通过哈希函数映射到数组元素的地址,通过数组地址一次性定位就可以完成了。哈希表是不允许有null值的。
刚才说了查找和增加元素是都是通过哈希函数计算出元素的地址进行保存和查找,如果新增元素遇到了计算出的地址是一样的,这样就出现了哈希冲突那么HashMap就通过 数据+链表的形式解决了这个问题。

  • 数据结构

根据第一张图和刚才的解释,已经说明了HashMap的数据结构是 数组+链表

  • 存储原理
    HashMap根据key的hashcode值存储数据。在存储和查询数据时可以直接定位到value,遍历顺序是不确定的。HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。
    在最新的jdk1.8中,HashMap增加了红黑树,数据结构变成了数组+链表+红黑树。HashMap的数组表的默认长度 length是16,负载因子是0.75.那么hashmap中允许最大数据量(存的键值数)就是 length*0.75。当超过这个数就会出现上文所说的hash冲突。那么这个时候就要在相同的key地址上增加链表。或则直接resize 重新扩容。扩容后的长度应该是原来长度的2倍。及时解决了扩容和链表,在jdk8中当链表默认长度是8当超过了8时链表就转换成了红黑树来提高hashmap的性能,因为链表和数据的时间复杂度是O(1),二叉树的时间为O(log)。红黑树的介绍。


3.确定HashMap索引位置

哈希算法 三步:取key的hashcode值,高位运算,取模运算。HashMap是由数组和链表的结合,如果hashmap中的元素位置分布均匀也就是map中没有hash冲突,就能直接通过hashcode确定到index和数据位置,不用遍历链表,大大优化了查询的效率。

4.hashmap的put方法和扩容机制

可以查看

https://tech.meituan.com/2016/06/24/java-hashmap.html