背景:
开发过程中,遇到需要写一个已知的hashmap,这种情况,为了防止hashmap在装载过程中,发生自动扩容,降低效率,都是要制定初始大小的;
前提:
根据本人知识储备,map的初始大小,默认为16,装载因子是0.75,即默认不指定的时候,最多可以存储12组键值对,当继续put第13组的时候,此时容量大小会扩展到32;
问题:
如果要存储3组键值对,那么根据上述情况,初始为4即可,代码实现测试,也确实如猜想
package javaBase;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
public class Learn01 {
public static void main(String[] args) throws InterruptedException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException {
HashMap map = new HashMap<Integer, String>(4);
for (int i = 0; i < 3; i++) {
map.put(i, "1");
}
display(map);
}
public static void display(HashMap map) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<? extends HashMap> aClass = map.getClass();
Field threshold = aClass.getDeclaredField("threshold");
threshold.setAccessible(true);
Method capacity = aClass.getDeclaredMethod("capacity");
capacity.setAccessible(true);
System.out.println("容量:" + capacity.invoke(map) + ";阈值:" + threshold.get(map) + ";元素数量:" + map.size());
}
}
输出结果
容量:4;阈值:3;元素数量:3
Process finished with exit code 0
谷歌提供了guava包里面有个Maps.newHashMapWithExpectedSize(int a)函数,可以实现,输入参数想要装载的键值对个数,自动设置初始大小,但是他的逻辑是a/0.75+1,放在上面的情况,a为3时,初始的大小将为5,hashmap自动识别2的倍数,即为8
//返回一个 新的、空的hashmap实例,有足够多(expectedSize个)的节点(entries),保证添加过程不出现resize
//@return a new, empty {@code HashMap} with enough capacity to hold {@code expectedSize} entries without resizing
public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {
return new HashMap<K, V>(capacity(expectedSize));
}
static int capacity(int expectedSize) {
if (expectedSize < 3) {
checkNonnegative(expectedSize, "expectedSize");
return expectedSize + 1;
}
if (expectedSize < Ints.MAX_POWER_OF_TWO) { //MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
// This is the calculation used in JDK8 to resize when a putAll
// happens; it seems to be the most conservative(保守的) calculation we
// can make. 0.75 is the default load factor.
return (int) ((float) expectedSize / 0.75F + 1.0F);
}
return Integer.MAX_VALUE; // any large value //MAX_VALUE = 0x7fffffff;
}