HashMap是无序且不安全的数据结构,HashMap是以key-value对的形式存储的,key值是唯一的(可以为null)一个key只能对应一个value,但Value是可以重复的;
HashMap如果再次添加相同的key值,它会覆盖key值对应的内容,这也是HashSet不同的一点,Set通过add添加相同的对象,不会添加到Set中去;
HashMap提供了get方法通过key值取对应的value值,但是HashSet只能通过Iterator来遍历数据,找对象
1. HashMap存储原理
1. 获取到传过来的key,调用hash算法获取到hash值
2. 获取到hash值之后调用indexFor方法,通过获取到hash值以及数组的长度算出数组的下标
3. 把传过来的key和value存到该数组下表当中
4. 如该数组下表已经有值了,则使用链表,jdk7是把新增元素添加到头部节点,jdk8则添加到尾部节点
2. HashMap存储流程
1. 第一种就是数组下标内容为空:put方法传进来的key和value包装成一个Node对象,存入
2. 数组下标内容不为空,但它引用的node还没有链化:这种情况下要先对比一下这个node对象的key与当前put对象的key是否完全相等,如果完全相等,进行replace操作,把之前槽位中的node下的value替换成新的value即可,否则的话这个put操作就是hash冲突,这种情况在slot槽位后边追加一个node即可,用尾插法
3. 第三种就是该数组下标内容已经被链化了:这种情况和第二种情况处理相似,首先也是迭代查找node,看看链表上中元素的key,与当前传过来的key是否完全一致,如果完全一致还是replace操作,用put过来的新value替换掉之前node中的value,否则的话就是一致迭代到链表尾节点也没有匹配到完全一致的node,就和之前一样,把put进来的数据包装成node追加到链表的尾部,再检查一下当前链表的长度,有没有达到树化阈值,如果达到了阈值就调用一个树化的方法,树化操作都是在方法里完成的。
4. 第四种情况就是冲突很严重的情况下,这个链表已经转化成红黑树了:TreeNode继承了Node结构,在Node基础上加了几个字段,分别指向父节点parent字段,指向左子节点left字段,指向右子节点right字段,还有一个表示颜色的red字段,这就是TreeNode结构;
红黑树的插入操作,首先找到一个合适的插入点,就是找到插入节点的父节点,然后红黑树它又满足二叉树的所有特性,所以查找这个父节点的操作和二叉树完全一致。二叉树排序,二分查找算法映射出来的结构,就是一个倒立的二叉树,然后每个节点都可以有自己的子节点,并且左子节点小于当前节点,右节点大于当前节点,然后每次向下查找一层排除掉一半数据,查找效率非常高,当然查找过程也分情况:
1. 首先第一种情况就是一直向下探测,直到查询到左子树或者右子树为null,说明整个树中,并没有发现Node链表中的key与当前put key一致的TreeNode,那此时探测节点就是插入父节点的所在了,然后就是判断插入节点的hash值和父节点的hash值大小决定插入到父节点的左子树还是右子树。当然插入还需要一个红黑树的平衡算法保持平衡;
2. 第二种就是根节点在乡下探测过程中发现treeNode中key与当前put的key完全一致,然后就也是一次replace操作,替换value