前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HashMap中的添加数据put方法:深入解析HashMap中的put方法——逐步揭秘数据添加过程

HashMap中的添加数据put方法:深入解析HashMap中的put方法——逐步揭秘数据添加过程

作者头像
猫头虎
发布2024-04-07 20:50:25
2180
发布2024-04-07 20:50:25
举报

导语

在Java中,HashMap是一种常用的数据结构,用于存储键值对。它的put方法是最常用的操作之一,本篇博客将深入探讨HashMapput方法,逐步分解每个步骤,以便更好地理解数据的添加过程。

1. 确定哈希桶位置

HashMap中,元素是通过哈希函数计算得到的哈希码(hash code)来确定存储位置的。put方法首先会根据键的哈希码计算出存储桶(bucket)的位置。

2. 判断桶是否为空

一旦确定了存储位置,HashMap会检查该位置是否已经存在元素。如果桶为空,表示该位置还没有元素,可以直接将新的键值对放入桶中。

3. 处理冲突

如果桶不为空,可能发生了哈希碰撞(hash collision),即不同的键计算得到相同的哈希码,需要通过链表或红黑树来解决。这里会根据桶内元素的数量以及HashMap的阈值来决定是否需要将链表转换为红黑树。

4. 替换或新增键值对

如果发生了冲突,HashMap会遍历链表或红黑树,检查每个节点的键是否与要添加的键相等。如果找到了相等的键,将会更新对应的值;如果没有找到相等的键,就在链表或红黑树的末尾添加一个新的节点。

5. 超过负载因子时进行扩容

在添加元素后,HashMap会判断当前的负载因子是否超过了阈值,如果超过了,就会触发扩容操作。扩容会创建一个更大的哈希表,并将原有的元素重新分配到新的桶中,以保持哈希表的均匀性。

代码演示:

代码语言:javascript
复制
//测试类
public class Test {
    public static void main(String[] args) {
    
        HashMap<Object, Object> map = new HashMap<>(); 
         //新建HashMap
         
        map.put(1,1);                   
           //添加数据--->进入此方法
           
    }
}
 public V put(K key, V value) {
 
        return putVal(hash(key), key, value, false, true);  
         //继续进入方法
         
    }
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
                   
        Node<K,V>[] tab; Node<K,V> p; int n, i;  
        //新建一个节点数组Node[],节点p,整形n,i
        
        if ((tab = table) == null || (n = tab.length) == 0)   
        //如果当前HashMap==null或者数组长度==0
        
            n = (tab = resize()).length;                       
            //扩容---n是当前容量
            
        if ((p = tab[i = (n - 1) & hash]) == null)       
         //如果根据当前键计算出的索引位置没有元素
           
            tab[i] = newNode(hash, key, value, null);         
            //把当前数据创建的新节点放到这个位置
            
        else {                                           
         //当前索引位置有元素
            Node<K,V> e; K k;                            
              //新建节点e   键类型变量k
            if (p.hash == hash &&                        
             //当前键值相等
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;                                    
                //把新节点p赋值给e
            else if (p instanceof TreeNode)              
             //否则  就判断p是不是树节点  是树节点调用树的put
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                
            else {                             
             //不是树节点就是链表
             
                for (int binCount = 0; ; ++binCount) {           
                 //循环 
                    if ((e = p.next) == null) {             
                      //如果当前节点也是尾节点  就把新节点追加到此处
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st   
                        //如果节点数>=边界值-1  
                            treeifyBin(tab, hash);               
                             //此时将链表转为红黑树
                        break;
                    }
                    if (e.hash == hash &&               
                    //判断在循环节点过程中如果有键值相等就结束循环-此时e存的是
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;                
                     //此时p或许是新节点并且被当前链表尾节点指向了  或许是p的节点的key与新节点的key相等了
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;          
                 //把旧值返回
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;           
                     //新值覆盖旧值
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;                       
           //此处++
        if (++size > threshold)            
         //此处判断是否达到边界值  是否扩容
            resize();
        afterNodeInsertion(evict);          
        return null;
    }

总结

HashMapput方法是一个复杂的过程,它涉及到了哈希桶的位置计算、冲突处理、链表转红黑树、键值对的替换与新增,以及在需要的情况下进行扩容等。了解这些步骤能够更好地理解HashMap的内部工作机制,为使用和优化HashMap提供了基础。

参考资料

  1. Java Platform SE 11 - HashMap Class
  2. Java HashMap working and internal implementation
  3. Understanding the internal implementation of HashMap in Java
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导语
  • 1. 确定哈希桶位置
  • 2. 判断桶是否为空
  • 3. 处理冲突
  • 4. 替换或新增键值对
  • 5. 超过负载因子时进行扩容
  • 代码演示:
  • 总结
  • 参考资料
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档