IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> HashMap底层分析(一) -> 正文阅读

[数据结构与算法]HashMap底层分析(一)

1、HashMap的底层

jdk1.7:数组 + 链表

jdk1.8:数组 + 链表 + 红黑树

2、关于HashMap的无参构造方法

(1).HashMap的无参构造方法采用延迟加载的方式来进行数组初始化的,默认长度是16,扩容因子为12

static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* (16) and the default load factor(因数、系数) (0.75).
*/
public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

这里并没有初始化数组,而是在put()方法的时候来完成数组的初始化的

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
transient Node<K,V>[] table;

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        //定义一个数组,Node<K,V>[] tab;
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        //判断当前数组是null,或者长度等于0
        if ((tab = table) == null || (n = tab.length) == 0){
            
            //resize()就是初始化方法
            tab = resize()
            n=tab.length;
        }         
    }

在这一行,Node<K,V>[] tab开始初始化。resize()中的部分代码

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

newCap = DEFAULT_INITIAL_CAPACITY;
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];

(2).初始化方法:resize()

final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;   //transient Node<K,V>[] table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;   //oldCap:0
        int oldThr = threshold;   //oldThr:0
        int newCap, newThr = 0;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }
        else if (oldThr > 0) // initial capacity was placed(设置,安置) in threshold
            newCap = oldThr;
        else {               // zero initial threshold signifies(表示,意思是) using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;   //newCap:16
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);   //newThr:12
        }
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;   //threshold:12
        @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];   //初始化一个容量为16的Node<K,V>的数组
        table = newTab;
        if (oldTab != null) {
        ......
        }
        return newTab;
    }

(3).threshold

threshold:扩容因子

  • 如果使用的是HashMap的无参构造器:
 Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        if (oldCap > 0) {
            //判断是否达到最大容量
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            //
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }

总结:

//扩容因子第一次
threshold = (newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY));//0.75 * 16 = 12
//数组容量第一次
newCap = DEFAULT_INITIAL_CAPACITY;//16   
    
//扩容因子第二次
threshold = (newThr = oldThr << 1);  //12 * 2 = 24
//数组容量第一次
newCap = oldCap << 1; //16 * 2 = 32

作用:数组是否扩容是通过threshold扩容因子来进行判断,但是是按照数组容量的两倍来进行扩容的!

  • 如果使用的是有参构造器HashMap(int initialCapacity, float loadFactor)
this.threshold = tableSizeFor(initialCapacity);  //扩容因子 = 扩容后的容量

3、关于HashMap的有参构造方法

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

有参构造器

public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);  //非法数据异常
        
        //如果初始化容量大于最大容量,则改变为最大容量2^30
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
    
        //如果装载因子小于等于0 或 装载因子为NaN ,则报错
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
    
        //通过这个方法可以实现提前设置一个较为稳定的容量,从而避免频繁扩容导致的性能下降
        this.threshold = tableSizeFor(initialCapacity);
    }

–>关于Float.isNaN(flaoat v)

public static boolean isNaN(float v) {
        return (v != v);
    }
 /*  
每个NaN都会分配一个单独的地址来放, 所以导致NaN==NaN的时候比较内存地址一定会返回false,也就是当且仅当v是NaN时NaN!=NaN一定是true
    
虽然Float.NaN==Float.NaN 结果为false,但Float.NaN与Float.NaN的equal()结果相等的
虽然0.0f==-0.0f结果为true,但0.0f 与 -0.0f的equals()结果是不等的;*/

扩容方法:tablesizefor()

当初始化HashMap时,如果指定了初始化容量initialCapacity,由于哈希桶的数量必须时2的n次幂,因此要把initialCapacity转化为

比它大的最小2的n次幂

如传入的initialCapacity=3,数组实际容量为4;传入的initialCapacity=5,数组实际容量为8;传入的initialCapacity=15,数组实际容量为16;

     /**
     * Returns a power of two size for the given target capacity.
     */
    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;
    }
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-11 00:02:37  更:2021-09-11 00:02:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:22:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码