深度分析HashMap的put方法源码

深度分析HashMap的put方法源码_第1张图片

深度分析HashMap的put方法源码_第2张图片

深度分析HashMap的put方法源码_第3张图片

它还会有一个哈希运算,就是为了避免哈希冲突。何为哈希冲突?不同的key值(也就是说是不同的对象),最终得到的hash值是相同的。造成锁定到同一个索引位置 。

深度分析HashMap的put方法源码_第4张图片

深度分析HashMap的put方法源码_第5张图片

 

 这里key即是我们传进来的new A(i),通过运行时绑定,可知调用的hashCode方法就是我们重写的

因为A这个类默认是继承Object这个类的。

hashCode方法是属于Object这个java类的,但是当子类重写了这个方法之后,我们每当调用这个方法,编译的时候看父类是否有这个方法,来决定是否编译的时候会报错。

然而运行的时候,是先从子类开始找这个hashCode方法,子类如果有,那么就使用子类的hashCode方法,如果子类没有,那么一层层的往父类,爷类进行寻找这个hashCode方法

 深度分析HashMap的put方法源码_第6张图片

 深度分析HashMap的put方法源码_第7张图片

接下来分析一下这个put底层的putVal方法

深度分析HashMap的put方法源码_第8张图片

深度分析HashMap的put方法源码_第9张图片底层先维护了一个静态内部类,原来维护Node节点。

在putVal添加的过程中我们,维护了一个Node[ ]  tab;数组,数组中将来放的每一个元素的类型就是Node类型,

为了把传进来的key,value值封装为一个Node节点对象存储在底层维护的ode[ ]  tab数组中深度分析HashMap的put方法源码_第10张图片

深度分析HashMap的put方法源码_第11张图片 开始分析:

深度分析HashMap的put方法源码_第12张图片

 如果一开始这个节点数组为空,那么我们就要进行扩容操作。

 当这个节点数组不为空之后,我们就可以通过计算算出该key对应的索引位置,hash值是通过key对象计算得来的。。。底层也会有一层计算索引的运算法则,如下图:

如果该位置没有节点,那么就直接插入

深度分析HashMap的put方法源码_第13张图片

  如果该位置有节点,

我们就要判断该位置已插入的节点和我们待插入的节点是否是相同的。。

如何判断它俩是否是相同的呢?

我们需要满足两个条件:

1.首先hash值必须相同。已插入Node节点对象的hash属性值和传进来的hash值相等

深度分析HashMap的put方法源码_第14张图片

2.接下来就要判断已插入Node节点对象的key属性值和传进来的key是否相同,类型为泛型。如果相同,那么就说明第二个条件成立。

如果说发现不相同,没关系,对于第二个条件,我们还有一个选择,满足就可以说明已插入的节点和待封装插入的是相同的,也就是key.equals(k)。

这个equals方法是Object类的方法

但是只要我们key对象所对应的类中重写这个equals方法,我们就会优先调用子类中重写父类Object的equals方法【运行时绑定】。所以说,这个equals比较规则可以由我们自己决定。

ok,如果说该equals方法返回true,那么就可以证明出是相同的啦!!

--但是记住,一切的前提就是先满足第一个条件!!

那么就会记录这个p,p在前面确定索引位置的时候已经赋过值了,见上一个图

---------------

小结:

我们知道hash值相同,不一定说明这俩就是同一个对象

但是同一个对象,所求出的hash值肯定是相同的。

所以说,当我们判断出hash值相等的时候,并不能百分比确定它俩就是同一个key对象,不能断定然后直接记录之后value值覆盖

所以说,我们要满足两个条件,

1.已插入Node节点对象的hash属性值和传进来的hash值相等

2.已插入Node节点对象的key属性值和传进来的key相同   或  当key不为空时,key通过equals方法返回true【第二个条件中满足一个就说明第二个条件成立!!!这是 "||"关系,如果前面的一个满足,后面就不用再看了。】

深度分析HashMap的put方法源码_第15张图片

-----------------

接下来继续

深度分析HashMap的put方法源码_第16张图片

 当发现待插入的key对象和该索引位置第一个节点对象不是同一个key对象的时候,我们就要进行情况判断,该索引位置处的节点成树状,那么就要进行树状式添加。

 如果是链条形式:

深度分析HashMap的put方法源码_第17张图片

 那么就要先遍历整个链条,

依次进行比较已插入的节点对象的hash属性和待封装为Node节点并插入

比较规则同上

深度分析HashMap的put方法源码_第18张图片

在遍历的过程中, 如果发现下一个索引位置处为null,那么直接封装传进来的key value hash 值封装为一个Node类型的节点。

深度分析HashMap的put方法源码_第19张图片

 但是当tab这个我们底层维护的数组的长度大于64,并且该链条长度大于等于8时,我们就要进行树化操作。目的就是为了提高查找性能,优化效率!

深度分析HashMap的put方法源码_第20张图片

 深度分析HashMap的put方法源码_第21张图片

 OK,结束!

你可能感兴趣的:(JavaSE,Java面试题,p2p,linq,gnu)