********本篇主要介绍基本数据结构与HashMap的put get方法大概原理********
一、相关数据结构介绍
1.数组结构
特点:存储区间连续、内存占用大
- 优点:通过数组下标可以快速定位想要查找的元素,从而可以快速高效率的进行查找与修改
- 缺点:①添加与删除数据效率低,因为数组元素是连续且具有下标的,删除一个数据或添加一个数据都会影响此数据之后的元素在内存中的位置(在最后一位添加除外) ②数组大小固定,动态扩展困难
2.链表结构
特点:存储区间离散、内存占用较宽松
- 优点:添加和删除速度快效率高,没有固定大小,方便扩容
- 缺点:不能定位查找某一想要的值,查找的话只能从头开始遍历直到找到所要找的元素停止,因此查询效率低
3.哈希表结构
特点:集数组和链表优点于一身,增删改查效率都高的一种数据结构,也就是散列表
由此数据结构引出文章的主角——HashMap
JDK1.7的结构是数组+链表
JDK1.8的结构是数组+链表+红黑树
当然我们要说的是1.8的啦~图如下:
二、HashMap源码刨析
让我们来看一下API是如何描述HashMap的:HashMap官方API
为了方便阅读我把方法截图了过来
HashMap中的put()和get()的实现原理:
1.map.put(k,v)实现原理
(1)首先,对table做null的检查,如果key是null,就创建一个新的table数组,并获取该数组的长度。
①Node[] table的初始化长度length(默认值为16)
②LodeFactor为负载因子(默认值为0.75)
③threshold是扩容阈值,HashMap所能容纳最大的键值对个数。
threshold = length * Load factor 也就是说,在数组定义好长度之后,负载因子越大,所能容纳的键值对个数越多。
(2)根据键值key计算hash值得到插入的数据索引i,如果table[i]==null,直接新建节点添加,如果下标对应的位置上有链表。此时,就会拿着k和链表上的每一个节点的k进行equals,如果所有的equals都返回false,那么这个新节点就插入到末尾,如果有一个equals返回true了,那么就覆盖这个点的value
(3)判断table[i]是否为TreeNode,也就是红黑树判断,若为红黑树则直接在树中插入键值对。
(4)若为链表,遍历table[i],判断链表长度是否大于TREEIFY_THRESHOLD(默认值为8),大于8的话就把链表转换成红黑树,在红黑树中执行插入操作,否则还是在链表操作。
(5)插入成功后,判断实际存在的键值对数量size是否超过了最大容量threshold,如果超过就进行扩容(resize)。
2.map.get(k)实现原理
(1)调用k的hashCode()方法或者哈希值,并通过哈希算法转换成下标。
(2)通过下标可以快速定位到table,如果位置上什么都没有就返回null,如果这个位置上是单向链表,那么就会拿着k和链表上的每个节点进行equals,如果都返回false,get就返回null。如果有一个节点能和k的equals返回true,那么此节点就是我们要找的,直接返回就ok了。
Tips:比较key元素需要重写equals方法,因为equals方法默认是比较两个对象的内存地址。
下一篇我会就着源码来逐一学习讲解,本博客仅供参考,本作者也是用来记录自己的学习情况和自身的理解,有错误的地方希望各位大佬谅解~~