Hashmap源码解析-构造函数

栏目: Java · 发布时间: 4年前

内容简介:构造函数:默认构造函数什么都不做,只是将加载因子设为默认加载因子。有初始值大小的构造函数,

#### 构造函数

构造函数:

默认构造函数什么都不做,只是将加载因子设为默认加载因子。

有初始值大小的构造函数,

​ 会将threshold设置为大于输入参数且最近的2的整数次幂的数,比如10,设置阈值16.

​ 即使有initialCapacity参数的构造,也是设置threshold,不会现在设置cap,如要设置cap就需要new资源了,而原理是在等真的插入的时候才去通过resize操作申请内存资源, 见resize.md,put.md

重点:

1.参数最大容量,默认的加载因子,加载因子,阈值

2.哈希桶, Node [] table, 是Node数组, 存放链表, 长度初始化时为0, 之后是2的N次方

3.loadFactor和threshold的关系

4.tableSizeFor函数的原理, 见下面解析

默认参数和构造函数源码:

//最大容量 2的30次方

static final int MAXIMUM_CAPACITY = 1 << 30;

//默认的加载因子

static final float DEFAULT_LOAD_FACTOR = 0.75f;

//哈希桶,存放链表。 长度是2的N次方,或者初始化时为0.

transient Node<K,V>[] table;

//加载因子,用于计算哈希表元素数量的阈值。  threshold = 哈希桶.length * loadFactor;

final float loadFactor;

//哈希表内元素数量的阈值,当哈希表内元素数量超过阈值时,会发生扩容resize()。

int threshold;

public HashMap() {

    //默认构造函数,赋值加载因子为默认的0.75f

    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted

}

public HashMap(int initialCapacity) {

    //指定初始化容量的构造函数

    this(initialCapacity, DEFAULT_LOAD_FACTOR);

}

//同时指定初始化容量 以及 加载因子, 用的很少,一般不会修改loadFactor

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;

    //显然加载因子不能为负数

    if (loadFactor <= 0 || Float.isNaN(loadFactor))

        throw new IllegalArgumentException("Illegal load factor: " +

                                            loadFactor);

    this.loadFactor = loadFactor;

    //设置阈值为  >= 初始化容量的最近的2的n次方的值

    this.threshold = tableSizeFor(initialCapacity);

}

//新建一个哈希表,同时将另一个map m 里的所有元素加入表中

public HashMap(Map<? extends K, ? extends V> m) {

    this.loadFactor = DEFAULT_LOAD_FACTOR;

    putMapEntries(m, false);

}

##### tableSizeFor函数的原理

tableSizeFor的功能(不考虑大于最大容量的情况)是返回大于输入参数且最近的2的整数次幂的数。比如10,则返回16.

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;

}

先来分析有关n位操作部分:先来假设n的二进制为01xxx…xxx。接着

对n右移1位:001xx…xxx,再位或:011xx…xxx

对n右移2为:00011…xxx,再位或:01111…xxx

此时前面已经有四个1了,再右移4位且位或可得8个1

同理,有8个1,右移8位肯定会让后八位也为1。

综上可得,该算法让最高位的1后面的位全变为1。

最后再让结果n+1,即得到了2的整数次幂的值了。

现在回来看看第一条语句:

int n = cap - 1;

让cap-1再赋值给n的目的是另找到的目标值大于或等于原值。例如二进制1000,十进制数值为8。如果不对它减1而直接操作,将得到答案10000,即16。显然不是结果。减1后二进制为111,再进行操作则会得到原来的数值1000,即8。

##### loadFactor和threshold的关系?

HashMap中size表示当前共有多少个KV对,capacity表示当前HashMap的容量是多少,默认值是16,每次扩容都是成倍的。loadFactor是装载因子,当Map中元素个数超过loadFactor capacity的值时,会触发扩容。loadFactor capacity可以用threshold表示。

好多地方都说threshold = loadFactor capacity, 但有初始值的初始化的时候,threadshold由tableSizeFor函数获得,这个地方之后 threshold 是什么时间进行的调整,应该是之后调整是根据loadFactor capacity。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

On LISP

On LISP

Paul Graham / Prentice Hall / 09 September, 1993 / $52.00

On Lisp is a comprehensive study of advanced Lisp techniques, with bottom-up programming as the unifying theme. It gives the first complete description of macros and macro applications. The book also ......一起来看看 《On LISP》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器