hashMap 1.7/1.8源码分析

本文详细分析了HashMap在Java 1.7和1.8版本中的实现,包括初始化过程、扩容策略、resize操作、clear方法、contains检查、clone行为等。在1.7中,HashMap在put时才初始化,1.8中扩容策略更加优化,涉及链表和红黑树的转换。
摘要由CSDN通过智能技术生成

1.7

在new HashMap() 的时候,不会初始化map,在对map进行put的时候才会初始化,初始化数组长度为传参initCapacity最邻近的一个2的n次方的数,如initCapacity=519时,数组长度为1024。

在第一次put值的时候,会进行初始化,步骤为

①计算数组长度,保证数组长度为2的n次方。

②计算扩容阈值,数组长度*负载因子。

③初始化数组,new Entry[capacity];

④判断是否需要hashSeed

每次会加在链表头部

当size大于阈值并且当计算出当前元素所属下标有值的时候才会进行resize();

还有当调用putAll时,参数map的size大于对象的阈值时,计算出参数map的capacity,并增大当前对象capacity,每次左移一位,直到thisCapacity>targetCapacity,最终如果thisCapacity大于table.length则会进行resize();

resize():

①进行判断,是否已经扩充到最大了,如果时则将阈值设置为int最大值。

②new一个新的数组 new Entry[newCapacity];

③将原来的数组值迁移到新的数组中;

遍历旧的数组,如果需要rehash则将数组中原来的每个元素rehash,并indexFor分散到newTable的各个index中

④计算新的阈值

clear方法调用Arrays.fill();将数组元素设为null。

判断contains,遍历数组+链表,找出对应值,如果存在则为true

clone()返回实例的浅拷贝,键和值本身没有拷贝。

 

1.8

resize()

判断旧容量如果大于0,说明map已经有元素到临界值需扩容

并且如果已经>=最大容量,增将阈值设置为int最大值返回;

如果旧容量两倍小于最大容量并且旧容量>=默认初始容量,则新阈值=旧阈值*2;

如果旧容量=0 且旧阈值大于0,说明map还没有put值,只是带参数new出来而已,则新容量=旧阈值

如果旧容量=0旧阈值也=0,则为无参new出来,初始化 新容量和阈值都为默认值

前面都走过了,如果新阈值=0,则计算新容量*加载因子 为新阈值,并赋值给属性;

创建新数组

如果旧数组不为空,则为扩容,需迁移元素

遍历旧数组,如果数组元素中只有一个node,则直接赋值到新数组的indexFor中,

如果元素是treenode 则调用split方法

 

其他则是链表

重新计算indexFor

//jdk1.8 map.put 
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        //如果table为null 则初始化table
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
    	//如果计算出的下标元素为null,就直接new个节点
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            //如果不为空 判断 key是否相等 相等说明存在 则直接替换value
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                //如果当前节点属于treeNode 则调用方法 创建树节点(存在则返回节点,不存在则创建新节点,返回null)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                //链表 遍历链表看是否存在key
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        //如果p下一个节点为空,则创建新节点 赋值
                        p.next = newNode(hash, key, value, n
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值