Java-HashMap的put()方法-源码详解

本文详细探讨了Java中的HashMap数据结构及其put()方法。HashMap是键值对的集合,JDK1.7前采用数组+链表,1.8后链表过长会转为红黑树。put()方法首先检查table是否需要初始化或扩容,接着计算key的hash值确定存储位置。如果位置为空,直接插入;否则,检查key是否已存在,存在则覆盖,不存在则插入。链表超过8个会转为红黑树,数组达到特定阈值会扩容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、HashMap是什么?

  • HashMap继承自Map接口,是键值对存储的一种集合。
  • JDK1.7之前底层使用数组+链表实现;JDK1.8之后当链表长度大于默认值8的时候,链表转换为红黑树
  • 一般的put()方法就是将key-value添加到HashMap当中,通过key的hashCode经过扰动函数后得到hash值就是在数组中的位置,之后判断数组中是否已经存在了当前的value,存在则覆盖,不存在通过拉链法解决
Map<Object,Obkect> hashmap = new HashMap<>();
hashmap.put(key,value);

2、put()方法具体经历了什么?

  1. HashMap首先判断table是否为null或长度为0,是的话则进行扩容,然后根据key计算hashCode(),得到存储key-value对的位置索引。

  2. 判断索引处是否为空,若为空,则直接插入到对应的数组中,

  3. 否则,判断key是否已存在,如果已存在则直接覆盖

  4. 否则,判断里面是链表还是红黑树,

    若是红黑树,则插入到红黑树;

    若是链表,则遍历链表插入,java8是将元素插入到链表尾部,

  5. 插入后,判断链表长度,若长度大于等于8,则将链表转为红黑树,

  6. 最后判断数组的size()是否大于等于门限值,是的话则进行扩容。

3、查看源码

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) {
    //tab: 引用当前hashMap的散列表
	//p: 表示当前散列表的元素
	//n: 表示散列表数组的长度
	//i: 表示路由寻址结果
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    // table未初始化或者长度为0,进行扩容(采用了延时初始化,第一次put才会初始化散列表。)
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    // 寻址找到的桶位为null
    //(n - 1) & hash 确定元素存放在哪个桶中,桶为空,新生成结点放入桶中(此时,这个结点是放在数组中)
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    // 寻址找到的桶位已经存在元素
    else {
        Node<K,V> e; K k;
        // 比较桶中第一个元素(数组中的结点)的hash值相等,key相等,也就是判断是否是重复的值。
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
                // 完全一致
            	//e:找到的一个与当前要插入的元素一直的元素
                e = p;
        // hash值不相等,即key不相等;且为红黑树结点
        else if (p instanceof TreeNode)
            // 放入树中
            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
                        treeifyBin(tab, hash);
                    break;
                }
                // 判断链表中结点的key值与插入的元素的key值是否相等
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    // 相等,跳出循环
                    break;
                // 用于遍历桶中的链表,与前面的e = p.next组合,可以遍历链表
                p = e;
            }
        }
        // 表示在桶中找到key值、hash值与插入元素相等的结点
        if (e != null) { 
            // 记录e的value
            V oldValue = e.value;
            // onlyIfAbsent为false或者旧值为null
            if (!onlyIfAbsent || oldValue == null)
                //替换
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    // 结构性修改
    ++modCount;
    // 实际大小大于阈值则扩容
    if (++size > threshold)
        resize();
    // 插入后回调
    afterNodeInsertion(evict);
    return null;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值