Java中Hashtable、HashMap、TreeMap的比较

发布时间 2023-12-25 00:00:04作者: Crazy_Joker

大家好,我是joker,希望你快乐。

最常见的Map实现,以键值对的形式存储和操作的数据容器。

Hashtable

Hashtable是同步的,不支持null键和值

HashMap

HashMap不是同步的,支持null键和值,内部数据结构为数组+链表组成的复合结构,如果链表的大小超过阈值(TREEIFY_THRESHOLD,8)就会被改造为树形结构。resize()方法负责初始化和扩容。putVal()方法包括很多逻辑如初始化,扩容,树化。阈值=负载因子*容量。以倍数调整容量及阈值。扩容后需要将老数组中的元素放到新数组中。

树化:当链表的长度超过阈值TREEIFY_THRESHOLD

如果总容量小于MIN_TREEIFY_CAPACITY,扩容

如果总容量大于MIN_TREEIFY_CAPACITY,树化

TreeMap

TreeMap不是同步的,基于红黑树的一种提供顺序访问的Map,具体顺序由Comparator或Comparable决定。

LinkedHashMap提供按插入顺序的遍历访问,通过维护一个双向链表

HashMap中的put,get方法分析

JDK1.8 HashMap

put方法操作

0.putVal方法获取hash值,调用hashcode方法,然后用获取到的hash值与自身高16位进行异或运算

1.先判断是否初始化过,如果没有初始化,调用resize方法进行初始化

2.用哈希值和数组长度-1进行与运算获取索引值,判断该位置是否已经存放Node,如果没有,创建Node存入

3.如果索引位置已经存放Node,判断key是否存在,如果存在,覆盖value值,返回旧值

4.如果key不存在,判断Node是否为TreeNode,如果是TreeNode,把Node转为TreeNode,存入红黑树中

5.如果不为树,则为链表,遍历链表,如果key存在,覆盖值,直到链表最后一个Node,创建新节点加入,如果链表个数大于8进行树化

6.treeifyBin树化内部判断数组是不是太小,如果太小不树化,先扩容

7.resize扩容,2倍扩容,扩容后数据移动,因为2倍扩容,数组长度-1求hash,所以元素会在原始位置或原始位置加数组原始长度

8.扩容元数据移动链表元素会在原始位置或原始位置加数组原始长度,树也是分高低位,根据节点数据量判断是否树化还是退化到链表

get方法操作

0.先判断容器中是否有元素,首节点是否有元素,没有直接返回null

1.如果有判断首节点key是否相等,相等返回首节点

2.如果首节点key不相等,判断后面是否有元素,没有直接返回null

3.如果有元素判断是树还是链表,查找,找到返回对应元素,未找到返回null

HashMap 1.7 1.8区别:1.7采用数组+链表,1.8采用数组+链表/红黑树,1.7采用头插法,1.8采用尾插法