一.回到Object万物之母
此时要将Student对象存储到HashMap的key上。
1.计算Student对象的哈希值,得到一个数组的索引下标hashCode()
2.判断当前这个Student对象是否已经在哈希表中存在了。是否是相同的key值=>equals>
class Student{
int age;
String name;
}
equals相同的两个对象 = 》hashcode是否应该相同
必须相同
hashCode相同的两个对象=》equals是否相同
不一定相同
equals相同的两个对象就认为是同一个对象,哈希表中这个对象有且只能有一个,经过哈希函数运算后,这俩对象保存的索引也应该相同
hashCode相同,说明发生哈希冲突,不一定是相同的对象,到底是否相同,还要取决于equals方法
在哈希表中,只有equals和hashCode都相同的对象,唯一对象。
stu1和stu3这两个对象的equals相同,此时在HashMap只会存储一份。相同的一个对象,equals相同的对象就认为是同一个对象
自定义对象作为key的唯一性就是通过equals来保证的
二.JDK的源码分析
2.1 HashMap的源码
put方法的逻辑,到底如何存储元素的
HashMap的哈希函数是如何设计的
当发生冲突时,如何解决的
哈希表冲突较严重,如何扩容resize
进入JDK的源码
KDK8之前,以及更老版本,HashMap就是数组+链表
2.关于HashMap源码中属性的解读
初始化的数组大小
默认的哈希桶数量(哈希桶就是哈希表中一个个的数组元素)
最大的数组容量2^30
默认的负载因子,默认最开始保存的元素个数最多为16*loadFactor = 12
树化阈值,某个哈希桶中的链表长度超过8才会触发“树化”操作
解树化,当某个哈希桶中的红黑树节点个数过小<=6时,就会将红黑树还原为链表
树化有两个条件
1.此时哈希表的哈希桶个数>=64
2.单个链表的节点个数>=8
若某个链表长度>=8
此时哈希桶的数量不足64
则只是简单的哈希表扩容而已
3.put方法
Ctrl+Alt+鼠标左键 选择实现子类的方法而不是接口
内部存储方法,首先计算一下当前key的哈希值
位运算的效率是最高的
得到哈希桶的编号
put核心流程
快捷键:
Ctrl +<-跳转到上一个浏览的位置
Ctrl ±>跳转到下一个浏览的位置
若自定义的类型需要保存到Map的key中,则需要同时覆写hashCode和equals
equals相同的俩对象。hashCode必须相同,反之不一定。