HashMap(get和put)jdk8

鼠扑  金牌会员 | 2022-9-16 17:24:52 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 951|帖子 951|积分 2853

get逻辑:
  1. HashMap数据结构为数组加链表加红黑树、只有当链表数量大于8时、才将链表转换为红黑树、时间复杂度由链表的O(N)转换为红黑树的O(logN)
  2. // 主要看getNode下的方法、传入key的hash值和key
  3. public V get(Object key) {
  4.     Node<K,V> e;
  5.     return (e = getNode(hash(key), key)) == null ? null : e.value;
  6. }
  7. // 返回一个Node对象、包含了key和value、在get方法中在返回value值
  8. final Node<K,V> getNode(int hash, Object key) {
  9.     // tab:Node<K, V>对象数组
  10.     Node<K,V>[] tab;
  11.     // first: 指向key hash值对应的数组值 e: first对应Node对象的下一个节点
  12.     Node<K,V> first, e;
  13.     // n: 指向当前HashMpa的数组长度
  14.     int n;
  15.     // k: 临时变量、指向 key
  16.     K k;
  17.     // 这里检测HashMap对象的数组是否存在、长度是否大于0、((n - 1) & hash)根据此表达式算出key对应的数组位置、在检查是否存在对象。
  18.     if (
  19.         (tab = table) != null &&
  20.         (n = tab.length) > 0 &&
  21.         (first = tab[(n - 1) & hash]) != null
  22.     ) {
  23.         // first当前值为一个Node节点
  24.         // 这个if是检测当前的first指向的Node是否是要获取的对象
  25.         // 直接判断first的hash值和要获取的hash值是否一直、并且key的值是否一直、通过 ==判断地址!=null和equals判断、key赋值为first的key
  26.         if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))
  27.             // 判断一致后直接返回要获取的Node节点给get、get在返回Node的value值
  28.             return first;
  29.         // 由于上面查找都查找不到、所以要查找Node的下一个节点、即查询链表或者红黑树
  30.         if ((e = first.next) != null) {
  31.             // 检查first对象是否是TreeNode(红黑树)
  32.             if (first instanceof TreeNode)
  33.                 // 当前first为红黑树对象、直接根据key调用内部的检索方法获取对应的value
  34.                 return ((TreeNode<K,V>)first).getTreeNode(hash, key);
  35.             do {
  36.                 // 链表查询、由于first上面判断过不是要查找的对象、e在上面语句已经指向first下一个节点、所以直接开始判断
  37.                 // 和上面的判断一样、检查hash值和key、qeuals判断、如果有则返回对应的Node对象、没有则最终执行下面的return null;语句。
  38.                 if (e.hash == hash &&
  39.                     ((k = e.key) == key || (key != null && key.equals(k))))
  40.                     return e;
  41.             } while ((e = e.next) != null);
  42.         }
  43.     }
  44.     // 表示当前对象并没有存储相关的key值、返回null
  45.     return null;
  46. }
复制代码
put逻辑
  1. public V put(K key, V value) {
  2.     // 内部调用putVal设置值、参数如下int hash, K key, V value, boolean onlyIfAbsent(如果为 true,则不更改现有值),boolean evict(如果为 false,则表处于创建模式)
  3.     return putVal(hash(key), key, value, false, true);
  4. }
  5. // 参数如下int hash, K key, V value, boolean onlyIfAbsent(如果为 true,则不更改现有值),boolean evict(如果为 false,则表处于创建模式)
  6. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  7.                boolean evict) {
  8.     // tab指向当前HashMap对象数组
  9.     Node<K,V>[] tab;
  10.     // p指向key的hash值所在的数组Node对象
  11.     Node<K,V> p;
  12.     // n:HashMap数组的长度、i:key的hash值对应的索引(index)
  13.     int n, i;
  14.     // 判断当前HashMap的数组对象是否为空、并且长度是否为0
  15.     if ((tab = table) == null || (n = tab.length) == 0)
  16.         // 分配数组空间并把长度返回给n
  17.         n = (tab = resize()).length;
  18.     // 计算hash对应的索引是否有对象存在、没有的话则创建Node对象、并将要put的值写入Node对象、在返回给数组
  19.     if ((p = tab[i = (n - 1) & hash]) == null)
  20.         tab[i] = newNode(hash, key, value, null);
  21.     // 要将Node对象写入到链表或者红黑树中
  22.     else {
  23.         // e: 代表最终你要写入的Node对象
  24.         Node<K,V> e;
  25.         // k: 指向hash值对象的Node节点的key
  26.         K k;
  27.         // 检查是否是同一个hash值、key是否相对或者进行equals判断
  28.         if (p.hash == hash &&
  29.             ((k = p.key) == key || (key != null && key.equals(k))))
  30.             // 代表同一个对象、赋值给e、最后在写入值
  31.             e = p;
  32.         // 检测是否是红黑树节点
  33.         else if (p instanceof TreeNode)
  34.             // 检测是红黑树对象、直接调用内部的写入方法、在返回一个Node<K, V>节点对象、最后在写入值、putTreeVal里面其实已经写入value了、后面在写入一次。
  35.             e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  36.         else {
  37.             // 链表操作、binCount检测有多少个链表节点、根据TREEIFY_THRESHOLD常量设定的值8、超过8个链表节点、则将该链表转换为红黑树
  38.             for (int binCount = 0; ; ++binCount) {
  39.                 //
  40.                 if ((e = p.next) == null) {
  41.                     p.next = newNode(hash, key, value, null);
  42.                     if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  43.                         // 将数组传入
  44.                         treeifyBin(tab, hash);
  45.                     break;
  46.                 }
  47.                 // 检测当前插入的对象是否一致、一致的话直接返回e、下面在将要写入的值赋值给变量e对象
  48.                 if (e.hash == hash &&
  49.                     ((k = e.key) == key || (key != null && key.equals(k))))
  50.                     break;
  51.                 p = e;
  52.             }
  53.         }
  54.         // 检测e对象是否不为空、不为空则下面写入对应的value值
  55.         if (e != null) { // existing mapping for key
  56.             V oldValue = e.value;
  57.             // onlyIfAbsent为true表示不更新对象
  58.             if (!onlyIfAbsent || oldValue == null)
  59.                 // 将值写入
  60.                 e.value = value;
  61.             afterNodeAccess(e);
  62.             return oldValue;
  63.         }
  64.     }
  65.     ++modCount;
  66.     // 当前数组长度自增1大于上次扩容长度后、重新扩容并且把重新扩容的大小赋值给threshold
  67.     if (++size > threshold)
  68.         // 重新调整数组长度
  69.         resize();
  70.     // LinkedHashMap中重写了、HashMap中没有具体实现
  71.     afterNodeInsertion(evict);
  72.     // 对应的key无法写入、返回null      
  73.     return null;
  74. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

鼠扑

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表