HashMap源码复习之基本参数与构造方法

最近复习Java基础,针对hashMap的底层代码,做了部分笔记,来帮助自己梳理其底层原理

//缺省Table大小
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

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

//缺省负载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;

//树化阈值
static final int TREEIFY_THRESHOLD = 8;

//树降级成为链表的阈值
static final int UNTREEIFY_THRESHOLD = 6;

//树化的另一个参数,当哈希表中的所有元素个数超过64时且达到树化阈值,才允许树化
//当Map里面的数量超过这个值时,表中的桶才能进行树形化,否则桶内元素太多时会扩容,而不是树形化为了避免进行扩容、树形化选择的冲突,这个值不能小于4*TREEIFYTHRESHOLD(8)
static final int MIN_TREEIFY_CAPACITY = 64;

//哈希表,存放元素的数组
transient Node<K,V>[] table;

//用来存放缓存
//存放具体元素的集合
transient Set<Map.Entry<K,V>> entrySet;

//当前哈希表中存放的元素个数
//存放元素的个数,注意这个不等于数组长度,size为HashMap中K-V的实时数量,不是数组table的长度
transient int size;

//当前哈希表结构修改次数
//每次扩容和更改map结构的计数器
transient int modCount;

//扩容阈值,当你的哈希表中的元素超过阈值时,触发扩容
int threshold;

//负载因子:threshold = capacity * loadFactor
//兼顾数组利用率又考虑链表不要太多,经过大量测试0.75是最佳方案
final float loadFactor;

无参构造

//构造一个空的HashMap,默认初始容量(16) 和默认负载因子(0.75)
//将默认的加载因子0.75赋值给loadFactor,并没有创建数组
public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

带参构造

//构造一个具有指定的初始容量和默认负载因子(0.75)
//指定“容量大小”的构造函数
public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

构造方法

//其实就是做了些校验
//capacity必须是大于0 ,最大值也就是 MAX_ CAP
//指定“容量大小”和“加载因子”的构造函数
initialCapacity:指定的容量
loadFactor:指定的加载因子
public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
            //loadFactor必须大于0
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
//构造一个映射关系与指定Map相同的新HashMap
public HashMap(Map<? extends K, ? extends V> m) {
        //负载因子loadFactor为默认的0.75
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
		//获取参数的长度
        int s = m.size();
        //判断参数集合的长度是否大于0
        if (s > 0) {
        	//判断table是否已经初始化
            if (table == null) { // pre-size
            	//未初始化,s为m的实际元素个数
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                //计算得到的t大于阈值,则初始化阈值
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            //已初始化,并且m元素个数大于阈值,进行扩容处理
            else if (s > threshold)
                resize();
             //将m中的所有元素添加至HashMap中
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }
注:    
	float ft = (float)s / loadFactor)+ 1.0F;这一行代码中为什么要加1.0F?
	s/loadFactor的结果是小数,1.0F(int)ft相当于是对小数做一个向上取整
	以尽可能的保证更大容量,更大的容量能够减少resize的调用次数。
	所以斤1.0F是为了获取更大的容量。
	例如:原来集合的元素个数是6个,那么6/0.758,2的n次幂,那么新的数组大小就是8了。
	然后原来数组的数据就会存储到长度是8的新的数组中了,这样会导致在存储元素的时候,
	容量不够,还得继续扩容,那么性能降低了,而如果+1呢,数组长度直接变为16了,这样可以减少数组的扩容。
//作用:返回一个大于等于当前值cap的一个数字,并且这个数字一定是2的次方数
//cap = 10
//n=10-1=>9
//0b1001	|	0b0100 => 0b1101
//0b1101	|	0b0011 => 0b1111
//0b1111	|	0b0000 => 0b1111
//15
//return 15+1;

//cap =16
//n=16;
//0b10000	|	0b01000 =>0b11000
//0b11000	|	0b00110 =>0b11110 
//0b111101  |	0b00001 =>0b11111 
//=>0b11111=>31
//return31+1;
//0001 1101 1100 => 0001 1111 1111 + 1 => 0010 0000 0000定 是2的次方数

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值