java之HashMap详解

HashMap是一个线程不安全的存储键值对的集合,基于Entry数组和链表或红黑树实现。它通过计算key的hashCode进行定位,当冲突严重时,链表会转换成红黑树。在put时,若key已存在,会检查并更新Value;当达到一定负载因子,HashMap会进行扩容,resize过程能有效减少冲突。get方法根据key的hashCode快速定位数据。初始化容量通常取2的幂次方以优化性能。

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

概览

HashMap的继承关系

这里写图片描述

java.lang.Object
   ↳     java.util.AbstractMap<K, V>
         ↳     java.util.HashMap<K, V>

public class HashMap<K,V>
    extends AbstractMap<K,V>

    implements Map<K,V>, Cloneable, Serializable {
   
    }

HashMap实现了Map接口,是一个存储键值对映射的集合,线程不安全,无序,键和值可以为null。

底层数据结构

这里写图片描述

HashMap的底层维护着一个Entry数组,即所谓的hash表,表中元素是Entry链表的第一个节点,链表中存储的是hash冲突的元素。
Java8后Entry改名为Node,并且当链表的容量达到一定值的时候转换成红黑树

源码解析

HashMap的静态属性值

//hash表默认容量:16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

//最大容量 
static final int MAXIMUM_CAPACITY = 1 << 30;

//装填因子,默认0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;

//将冲突链表转为红黑树的阈值
static final int TREEIFY_THRESHOLD = 8;

//由红黑树转链表时,数节点的阈值, 小于这个阈值才能转为链表
static final int UNTREEIFY_THRESHOLD = 6;

//能将链表转为红黑树的最小hash表容量。应该至少4倍于 TREEIFY_THRESHOLD
//即只有当 冲突链表节点数大于等于8 且 hash表容量达到64时才将链表转为红黑树
static final int MIN_TREEIFY_CAPACITY = 64;

put()方法

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

这里直接调用了 hash() 方法计算 key 的hash值 并调用 putVal() 方法

计算hash

static final int hash(Object key) {
      int h;
      return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

keynull ,其hash值为0.

h = key.hashCode()计算出 key 的hash值,h >>> 16 是因为计算出的hash值是32位的,将h无符号右移16位,再与原值异或运算。得到的新hash值的高16位较h的原值不变,原值的低16位和高16位进行了异或运算。

这么做的主要目的在于,当hash数组较小时,hash值的所有bit位都参与了运算,防止hash冲突太大。

putVal()详解

//hash: 当前key的hash值, onlyIfAbsent:是否覆盖重复值,hashMap 里面是false,evict:没用。。
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值