常州网站建设专业的公司,黑龙江网站开发,wordpress功能详解视频教程,晋江网站建设qzdzi文章目录 ⭐容器继承关系#x1f339;Map容器#x1f5d2;️HashTable源码解析构造方法put方法remove方法rehash扩容 #x1f5d2;️HashMap源码解析构造函数get方法put方法详解 扩容方法详解 #x1f5d2;️TreeMap源码解析 ⭐容器继承关系 #x1f339;Map容器
键值对映… 文章目录 ⭐容器继承关系Map容器️HashTable源码解析构造方法put方法remove方法rehash扩容 ️HashMap源码解析构造函数get方法put方法详解 扩容方法详解 ️TreeMap源码解析 ⭐容器继承关系 Map容器
键值对映射Map容器中的元素是以键值对的形式存储的每个键对应一个值。通过键可以快速查找对应的值。
键不重复Map中的键是唯一的每个键对应一个值。如果添加已经存在的键则会更新对应的值。
常用操作Map提供了添加键值对、获取值、判断是否包含某个键等基本操作。
遍历可以通过键集、值集或者键值对集合来遍历Map中的元素。
️HashTable源码解析
线程安全Hashtable 是同步的可以在多线程环境中安全地使用。这意味着多个线程可以同时读写 Hashtable 而不会出现并发问题。
不允许 null 键或值Hashtable 不允许键或值为 null如果尝试插入 null 键或值会抛出 NullPointerException 异常。
初始容量和加载因子Hashtable 有一个初始容量和加载因子当哈希表中的元素数量超过加载因子乘以容量时哈希表会自动扩容。
构造方法 默认容量是11加载因子是0.75 指定装载容量加载因子是0.75 如果用户传入的initialCapacity为0将初始容量设为1确保哈希表至少有一个桶用于存储元素。 计算哈希表的扩容阈值其值为initialCapacity乘以loadFactor的结果与MAX_ARRAY_SIZE 1之间的较小值。当哈希表中的元素数量超过这个阈值时会触发扩容操作以保证哈希表的性能。
在函数内部首先根据传入的map的大小计算出一个初始容量并将其和11中的较大值作为Hashtable的容量并设置加载因子为0.75。然后调用putAll方法将传入的map中的所有键值对复制到新创建的Hashtable中。
put方法 将指定的键key映射到指定的值value并将其添加到哈希表中。如果该键已经存在于哈希表中则用新值替换旧值并返回旧值。如果该键不存在则将新键值对添加到哈希表中。该方法是同步的可以避免多线程环境下的并发问题。需要注意的是键和值都不能为null。
hash 是传入键对象Key的hashCode值。 0x7FFFFFFF 是一个32位的整数其二进制表示为一串1与操作符 “” 用来获取 hash 的正向32位整数值确保结果非负。 % tab.length 是对得到的无符号32位整数取模运算目的是将哈希码映射到哈希表的实际索引位置上这样即使哈希表大小不同也能保证键均匀分布。 整体来说这段代码的作用是根据给定的键对象的hashCode值确定其在哈希表数组中的索引位置。
remove方法 rehash扩容 获取旧哈希表的容量和映射数组。 计算新哈希表的容量当新容量超过最大数组大小时将其设置为最大数组大小。 创建新哈希表映射数组。 更新哈希表的修改次数和阈值。 将旧哈希表中的每个键值对重新哈希到新哈希表中。
️HashMap源码解析
非线程安全HashMap 不是同步的因此不适合在多线程环境中直接使用。如果需要在多线程环境中使用可以通过 Collections.synchronizedMap 方法来创建一个线程安全的 Map。
允许 null 键和值在 Java 8 之后HashMap 允许 null 作为键和值。
初始容量和负载因子HashMap 有一个初始容量和负载因子。当哈希表中的元素数量超过负载因子乘以容量时哈希表会自动扩容。
构造函数 这一段代码和上面HashTable的构造函数很像
get方法 首先根据哈希值和表的长度计算出节点在表中的索引位置然后获取该位置上的节点。如果该节点存在并且与 给定的键 相等则返回该节点。如果该节点存在但是是一个TreeNode红黑树节点则将获取节点的操作委托给TreeNode的getTreeNode方法。如果该节点存在但是下一个节点不为空则遍历下一个节点重复上述判断操作直到找到相等的节点或者遍历结束。如果在整个表中找不到相等的节点则返回null。
put方法 详解 NodeK,V[] tab中tab表示的就是数组。NodeK,V p中p表示的就是当前插入的节点 如果数组是空的那么就通过resize方法来创建一个新的数组 i表示在数组中插入的位置计算的方式为(n - 1) hash。在这里需要判断插入的位置是否是冲突的如果不冲突就直接newNode插入到数组中即可
如果冲突了进入下面的分析 判断table[i]中的元素是否与插入的key一样若相同那就直接使用插入的值p替换掉旧的值e。 判断插入的数据结构是红黑树还是链表在这里表示如果是红黑树那就直接putTreeVal到红黑树中
如果是链表就进入下面的分析
如果数据结构是链表首先要遍历table数组是否存在如果不存在直接newNode(hash, key, value, null)。如果存在了直接使用新的value替换掉旧的。
注意一点不存在并且在链表末尾插入元素的时候会判断binCount TREEIFY_THRESHOLD - 1。也就是判断当前链表的长度是否大于阈值8如果大于那就会把当前链表转变成红黑树方法是treeifyBin 插入成功之后还要判断一下实际存在的键值对数量size是否大于阈值threshold。如果大于那就开始扩容了。
扩容方法 详解 首先如果超过了数组的最大容量那么就直接将阈值设置为整数最大值然后如果没有超过那就扩容为原来的2倍这里要注意是oldThr 1移位操作来实现的。
第一个else if表示如果阈值已经初始化过了那就直接使用旧的阈值。然后第二个else表示如果没有初始化那就初始化一个新的数组容量和新的阈值。
️TreeMap源码解析
有序性TreeMap中的键值对根据键的自然顺序或自定义排序规则进行排序因此可以按照键的顺序进行遍历。
红黑树TreeMap内部使用红黑树作为数据结构这种自平衡二叉搜索树能够保持键值对的有序性并且提供了较快的插入、删除和查找操作。
键的唯一性TreeMap中的键是唯一的如果尝试插入一个已存在的键则会覆盖原有的值。
性能TreeMap提供了对数时间复杂度的插入、删除和查找操作适合于需要有序存储和查找的场景。
导航方法TreeMap提供了许多导航方法如firstKey()、lastKey()、lowerKey(K key)、higherKey(K key)等可以方便地进行范围查找和导航操作。