目录
HashMap
1 什么时候才需要扩容
当HashMap中的元素个数超过数组大小(数组长度)*loadFactor(负载因子)时 就会进行数组扩容loadFactor的默认值(DEFAULT_LOAD_FACTOR)是0.75 这是一个折中的取值 也就是说 默认情况下 数组大小为16
那么当HashMap中的元素个数超过16×0.75=12(这个值就是阈值或者边界值threshold值)的时候 就把数组的大小扩展为2×16=32 然后重新计算每个元素在数组中的位置 而这是一个非常耗性能的操作 所以如果我们已经预知HashMap中元素的个数 那么预知元素的个数能够有效的提高HashMap的性能
2 HashMap默认给多少容量合适
测试发现 当数组put到第12个数据时(当前数据>容量*0.75) HashMap进行了扩容
扩容倍数为当前数据大小的最小二次幂
所以 在已知数据量大小时 取当前数的最小二次幂 不知道容量大小 可以自行估算
public void HashMapTest() throws Exception {
System.out.println(NumberUtils.hapMapRightSize(20));
HashMap<String, Integer> map = new HashMap<>();
// HashMap<String, Integer> map = new HashMap<>(NumberUtils.hapMapRightSize(20));
for (int i = 0; i <= 20; i++) {
map.put(Integer.toString(i), i);
System.out.println("map size = " + map.size() + ", map capacity = " + getHashMapCapacity(map));
}
}
/**
* 获取HashMap定义容量
*
* @param map
* @return
* @throws Exception
*/
public static int getHashMapCapacity(HashMap<?, ?> map) throws Exception {
Field table = HashMap.class.getDeclaredField("table");
table.setAccessible(true);
Object[] obj = (Object[]) table.get(map);
return obj.length;
}
/**
* 获取这个数最小2次幂(2进制方法)
*
* @param num
* @return
*/
public static int rebuildNums(int num) {
int max = 1 << 30;
int n = num - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return n < 0 ? 1 : (n >= max ? max : n + 1);
}
/**
* 估算HashMap最合适初始容量
*
* @param num
* @return
*/
public static int hapMapRightSize(int num) {
int i = rebuildNums(num);
if (num > 0.75 * i) {
return i * 2;
} else {
return i;
}
}
给定初始值后 塞入值时HashMap不再扩容 所以当数据量很大的时候 节省了很多扩容时间
ArrayList
1 什么时候才需要扩容
当数组的大小大于初始容量的时候(初始为10 当添加第11个元素的时候)就会进行扩容 新的容量为旧的容量的1.5倍)
2 ArrayList默认给多少容量合适
基于每次扩容为上次容量的1.5倍 我们可以给定初始值为容量的1.5倍
/**
* 获取list定义容量
*
* @param al
* @return
* @throws Exception
*/
public static int getListCapacity(List<?> al) throws Exception {
Field field = ArrayList.class.getDeclaredField("elementData");
field.setAccessible(true);
return ((Object[]) field.get(al)).length;
}
public void test120() throws Exception {
// List<Integer> list = new ArrayList<>();
List<Integer> list = new ArrayList<>(NumberUtils.arrayListRightSize(20));
for (int i = 0; i < 20; i++) {
list.add(i);
System.out.println("list size = " + list.size() + ", list capacity = " + getListCapacity(list));
}
}
/**
* 估算Arraylist 最适合初始容量
*
* @param num
* @return
*/
public static int arrayListRightSize(int num) {
if (num > 0) {
//向上取整
return (int) Math.ceil(1.5 * num);
} else {
return 10;
}
}
给定初始容量后 再次测试 发现并没有触发扩容 当不知道具体数据量时 可以自行估算哦
在此HashMap和ArrayList定义最佳初始容量已经介绍完了
如果有什么不对的 欢迎小伙伴们指正哦 欢迎留言讨论😋