HashMap是Java中的一种集合类,其底层数据结构对于理解其工作原理至关重要。以下是对HashMap底层数据结构的介绍,以及put方法时插入到链表或覆盖value的情况说明:
HashMap底层数据结构
HashMap的底层数据结构主要由数组和链表(或红黑树)组成:
- 数组:HashMap底层实际上是一个一维数组,数组的每个元素都是一个Node(在JDK 1.8及之后版本中称为Node,而在JDK 1.7及之前版本中称为Entry)。数组用于存储哈希表的桶(Bucket),桶中可能包含一个或多个键值对(Key-Value Pair),这些键值对通过链表(或红黑树)来组织。
- 链表(或红黑树):当多个键值对的哈希值相同(即发生冲突)时,它们会被添加到同一个桶中,并通过链表来链接。在JDK 1.8及之后版本中,当链表长度超过一定阈值(默认为8)且数组长度大于64时,链表会转换为红黑树,以提高查询性能。
put方法的工作原理及插入到链表或覆盖value的情况
当调用HashMap的put方法时,会执行以下步骤:
- 计算哈希值:首先,根据key的hashCode()方法计算其哈希值。然后,使用哈希值与数组长度减一的位运算结果作为数组的索引(即桶的位置)。
- 判断桶是否为空:如果桶为空,则直接创建一个新的Node(或Entry),并将其放入桶中。
-
桶不为空的情况:
-
链表节点:如果桶中已经有节点,且该节点为链表节点,则会遍历链表,查找是否存在与当前key相同的节点。
- 如果找到相同key的节点,则直接覆盖其value值(即更新value)。
- 如果未找到相同key的节点,则将新的Node添加到链表的末尾(在JDK 1.8及之后版本中使用尾插法)。
- 红黑树节点:如果桶中的节点已经转换为红黑树,则会按照红黑树的规则进行插入或更新操作。
-
链表节点:如果桶中已经有节点,且该节点为链表节点,则会遍历链表,查找是否存在与当前key相同的节点。
- 判断是否需要扩容:在插入新节点后,会判断HashMap的当前大小是否超过了阈值(即加载因子与数组长度的乘积)。如果超过阈值,则会对数组进行扩容操作。
插入到链表或覆盖value的原因
- 插入到链表:当桶中已经有节点,且新节点的key与桶中已有节点的key不同(即哈希值相同但key不同)时,新节点会被添加到链表的末尾(或红黑树中)。这是为了处理哈希冲突,即多个key具有相同的哈希值但需要被存储在HashMap中的情况。
- 覆盖value:当桶中已经有节点,且新节点的key与桶中已有节点的key相同时,新节点的value会覆盖旧节点的value。这是HashMap的一个特性,即对于相同的key,后插入的value会覆盖先插入的value。
综上所述,HashMap的底层数据结构由数组和链表(或红黑树)组成,用于处理哈希冲突和存储键值对。在put方法中,根据key的哈希值确定桶的位置,并根据桶中已有节点的情况进行插入或更新操作。