的与运算(n 为数组长度)得到key 所在数组的下标,如果该下标位置存在其他元素,即发生了哈希碰撞,HashMap 会在发生碰撞的位置采用链表法来存储(即将具有相同hash 值的元素存储在同一个链表中),即便这两个元素不相等也会存储,只是通过key 的equals 方法来区分这两个 key-value,但在使用时如果不重写equals 方法将会导致相同hash 值的多个对象同时存在于链表中,而只有一个会被get 方法获取。JDK1.8 之后在兼顾之前的基础上,加入了红黑树,当链表长度超过8 且数组长度大于64 时,链表转为红黑树。
HashMap 源码分析构造方法HashMap 的构造方法非常简单,具有以下几种构造方法:1.public HashMap():构造一个初始容量为 16,加载因子为 0.75 的空HashMap2.public HashMap(int initialCapacity):构造一个指定初始容量,加载因子为 0.75 的空HashMap3.public HashMap(int initialCapacity, float loadFactor):构造一个指定初始容量,指定加载因子的空HashMap4.public HashMap(Map<? extends K,? extends V> m):构造一个包含指定Map 中所有元素的新HashMapput 方法put 方法是HashMap 中用于添加元素的方法,具体过程如下:1.判断table 数组是否为空,如果为空,则调用resize()方法进行初始化2.计算key 的hash 值3.通过(key 的hash 值与数组长度-1)的与运算得到key 所在的bucket(数组下标位置)4.如果该bucket 位置存在元素,则判断元素的 hash 和 key 与要添加元素的hash 和 key 是否相等,若相等则覆盖value值,若不相等则判断该元素是链表节点还是树节点:如果是链表节点,则直接在链表尾部添加该元素;如果是树节点,则通过TreeNode 的 putTreeVal 方法进行插入5.若该bucket 位置不存在元素,则直接添加元素6.判断当前HashMap 中的size 是否大于threshold(容量*加载因子),若大于则进行resize()方法resize 方法resize 方法是HashMap 中用于扩容的方法,具体过程如下:1.判断当前数组是否为空,如果为空则初始化一个长度为16 的数组2.创建一个长度为原数组两倍的新数组newTab 3.遍历原数组,将原数组的元素重新计算hash 值,然后通过 (n-1) & hash 来确定新数组的位置4.将元素插入到新数组中5.如果链表长度大于8 且数组长度大于64,则将链表转为红黑树get 方法get 方法是HashMap 中用于获取元素的方法,具体过程如下:1.计算key 的hash 值2.通过(key 的hash 值与数组长度-1)的与运算得到key 所在的bucket(数组下标位置)3.若该bucket 位置为空,则返回null4.若该bucket 位置不为空,则遍历链表或红黑树查找对应的key 值并返回相应的value值HashMap 常用方法测试HashMap 的常用方法包括put、get、resize 等,我们可以通过简单的测试代码来验证HashMap 的基本功能,例如:```javaHashMap<String, String> map = new HashMap<>();map.put("apple", "red");map.put("banana", "yellow");System.out.println(map.get("apple"));//输出 red```感谢changfubai 对本文的改进做出的贡献!感谢对本文做出改进的changfubai同学,在他的帮助下,本文得以更加完善,希望读者们在学习过程中有所收获。以上就是关于HashMap(JDK1.8)源码分析的全部内容,希