hashmap value可以为空吗_HashMap关键点分析

基于JDK版本:1.8一、核心概念数据结构:从jdk1.8之后,HashMap采用数组+链表+红黑树(Red-Black Tree)。因为这个特性,HashMap的查询时间复杂度理论上为O(1),但实际上是:O(1)+O(n)+O(logn),因为链表长度大于(TREEIFY_THRESHOLD = 8 )会自动转成红黑树,所以当数据Key的哈希值冲突时,时间复杂度将会达到O(logn)...
摘要由CSDN通过智能技术生成

基于JDK版本:1.8

一、核心概念
  1. 数据结构:从jdk1.8之后,HashMap采用数组+链表+红黑树(Red-Black Tree)。因为这个特性,HashMap的查询时间复杂度理论上为O(1),但实际上是:O(1)+O(n)+O(logn),因为链表长度大于(TREEIFY_THRESHOLD = 8 )会自动转成红黑树,所以当数据Key的哈希值冲突时,时间复杂度将会达到O(logn)。

  2. key和value可以为null,但key只能存在一个null,位于组数的0位置:因为hash(key)方法,当key=null ,返回0。存储对象时,存储为key的对象需要重写equals()方法。

  3. 线程不安全,多线程高并发情况下,容易形成 循环链表。高并发场景可以使用Collections.synchronizedMap(Map map) 方法使 HashMap 具有线程安全的能力,或者使用 ConcurrentHashMap。

  4. HashMap初始容量为16,超过:扩容阈值(threshold) = 哈希表容量 * 加载因子(load factor) 进行扩容, 每次扩容2的倍数。且保证容量为2^n个数

  5. HashMap JDK1.8 中扩容后,只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap。在 1.7的时候扩容后,链表的节点顺序会倒置,1.8则不会出现这种情况。

  6. hash方法的区别:HashMap 会对 key 的 hashCode 返回值做进一步扰动函数处理。

  • 1.7 中扰动函数使用了 4次位运算 + 5次异或运算;

  • 1.8 中降低到 1次位运算 + 1次异或运算;;

    扰动处理后的 hash 与 哈希表数组length -1 做位与运算得到最终元素储存的哈希桶角标位置。

HashMap数据结构

3d7c511d5b2158a944de3acb1ef3913d.png

二、关键参数
//默认初始化容量,保证为2的倍数。
static final int DEFAULT_INITIAL_CAPACITY = 1 <4; // aka 16
//最大容量
static final int MAXIMUM_CAPACITY = 1 <30;
//默认加载因子:如果因子太小,则会频繁扩容,因子太大,则键冲突多,转成链表或树。
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//触发转成树时链表(桶)的临界阈值,大于2,小于8.
static final int TREEIFY_THRESHOLD = 8;
//转成链表时树的个数临界阈值
static final int UNTREEIFY_THRESHOLD = 6;
//转成树时数组的个数,至少为4*TREEIFY_THRESHOLD,才能避免扩容与转换成树冲突。
//在treeifyBin()方法内有判断
static final int MIN_TREEIFY_CAPACITY = 64;

//加载因子,如果未指定使用的是,DEFAULT_LOAD_FACTOR——无参构造方法
final float loadFactor;
//库容阈值 = 容量 * 加载因子
int threshold;
//存储哈希桶的数组,哈希桶中装的是一个单链表或一颗红黑树,长度一定是 2^n
transient Node[] table;//所有键值对的Set集合 区分于 table 可以调用 entrySet()得到该集合transient Set> entrySet;//HashMap中存储的键值对的数量注意这里是键值对的个数而不是数组的长度(table.length)transient int size;操作数记录 为了多线程操作时 Fast-fail 机制transient int modCount;
三、主要方法
  1. 构造方法

    主要决定两个参数:loadFactor和threshold。

    其中threshold通过方法:tableSizeFor(initialCapacity)得到

    static final int tableSizeFor(int cap) {
           
            int n = cap - 1;
            n |= n >>> 1;
            n |= n >>> 2;
            n |= n >>> 4;
            n |= n >>> 8;
            n |= n >>> 16;
            return (n 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
        }

    该方法永远返回一个 <

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值