JDK源码分析

文章7 |   阅读 2981 |   点赞0

来源:https://blog.csdn.net/u010188178/category_8235178.html

JDK源码分析--HashMap的扩容

x33g5p2x  于2021-12-18 转载在 其他  
字(1.9k)|赞(0)|评价(0)|浏览(408)

面试时老生常谈的问题:请问HashMap在什么时候扩容?

稍稍看过源码的立马回答:默认装载因子0.75,当size达到总容量的0.75时会扩容。

而事实如此吗?经实验证明,不一定,还需要看JDK的版本

HashMap中有一个重要的属性叫threshold,扩容临界值,即下一个要调整大小的值(总容量*装载因子)。

一、以JDK1.7为例

      查看源码,在put操作时扩容的条件为“(size >= threshold) && (null != table[bucketIndex])”,也就是说还需要同时满足后面条件,那么bucketIndex又是什么呢?直译为“桶的下标”,即下一个存放Entry的桶的位置,这个位置的获取来自方法“indexFor”,如下:

static int indexFor(int h, int length) {//hash值,table的总容量
    return h & (length-1);
}

length-1的二进值各位都是1,h & (length-1)的与运算,实质就是h% (length-1),只要hash不相等,理想情况下,需要容量被全部占用时才会扩容。

简而言之,仅当size >= threshold且发生Hash值%(length-1)冲突(或修改已存在的值或)时,才会进行扩容。

二、JDK1.8

      查看源码,判断条件如下:

if (++size > threshold)
            resize();

      当下一个元素添加进来时,size大于扩容临界值时,对HashMap进行扩容操作。因此如果说是1.8及以上版本的JDK,可以回答“默认装载因子0.75,当size达到总容量的0.75时会扩容”。

三、在JDK1.7版本证明上述言论的正确性

1、测试代码,为了促使key的hashcode容量冲突(这里不是指hash冲突,而是key本身就是一个值,目的就是证明key冲突是扩容的第二条件),使用100以内的随机整数作为key。

public static void testHashMap2() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
	int size = 7;
	HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(size);
	Class<? extends HashMap> class1 = null;
	Field field = null;
	Entry<Integer, Integer>[] table = null;
	int threshold = size;
	for(int i=1; i<= 100; i++){
		class1 = map.getClass();
		field = class1.getDeclaredField("threshold");
		field.setAccessible(true);
		threshold = field.getInt(map);
		System.out.print("添加元素前:i="+i);
		System.out.print("  扩容临界值threshold:"+threshold);
		System.out.print("  键值对大小size:"+map.size());
		
		field = class1.getDeclaredField("table");
		field.setAccessible(true);
		table = (Entry<Integer, Integer>[])field.get(map);
		System.out.println("  总容量table大小:"+table.length);
		map.put((int)(Math.random()*100), (int)(Math.random()*100));
	}
}

2、运行可以看到以下内容

注意,输出以下内容是在插入元素前;如果输出有size重复的情况,说明是同一个key):

(1)第一次扩容,当插入第6个元素时扩容到16(扩容前临界值为6)

(2)第二次扩容,当插入第17个元素时才扩容到32(扩容前临界值为12)

(3)第三次扩容,当插入第25个元素后扩容到64(扩容前临界值为24)

多次运行会有不同的结果,足以说明JDK1.7的扩容点具有一定的随机性。

以上观点仅供参考,如有疑义,请联系作者,万分感谢!

相关文章