AHashMap的文档中有这样一句话:
如果初始容量大于最大条目数除以负载因子,则不会发生重新哈希操作。
请注意文档如何说rehash,而不是调整大小- 即使 rehash 只会在调整大小时发生;那是当桶的内部大小变成两倍大时。
当然也HashMap提供了这样一个构造函数,我们可以在其中定义这个初始容量。
构造一个具有指定初始容量和默认负载因子 (0.75) 的空 HashMap。
好的,看起来很简单:
// these are NOT chosen randomly...
List<String> list = List.of("DFHXR", "YSXFJ", "TUDDY",
"AXVUH", "RUTWZ", "DEDUC", "WFCVW", "ZETCU", "GCVUR");
int maxNumberOfEntries = list.size(); // 9
double loadFactor = 0.75;
int capacity = (int) (maxNumberOfEntries / loadFactor + 1); // 13
所以容量是13(在内部是16- 下一个 2 的幂),这样我们就可以保证文档部分没有重新哈希。好的,让我们测试一下,但首先介绍一个方法,该方法将进入 aHashMap并查看值:
private static <K, V> void debugResize(Map<K, V> map, K key, V value) throws Throwable {
Field table = map.getClass().getDeclaredField("table");
table.setAccessible(true);
Object[] nodes = ((Object[]) table.get(map));
// first put
if (nodes == null) {
// not incrementing currentResizeCalls because
// of lazy init; or the first call to resize is NOT actually a "resize"
map.put(key, value);
return;
}
int previous = nodes.length;
map.put(key, value);
int current = ((Object[]) table.get(map)).length;
if (previous != current) {
++HashMapResize.currentResizeCalls;
System.out.println(nodes.length + " " + current);
}
}
现在让我们测试一下:
static int currentResizeCalls = 0;
public static void main(String[] args) throws Throwable {
List<String> list = List.of("DFHXR", "YSXFJ", "TUDDY",
"AXVUH", "RUTWZ", "DEDUC", "WFCVW", "ZETCU", "GCVUR");
int maxNumberOfEntries = list.size(); // 9
double loadFactor = 0.75;
int capacity = (int) (maxNumberOfEntries / loadFactor + 1);
好吧,resize被调用,因此条目被重新哈希,而不是文档所说的。
如上所述,密钥不是随机选择的。这些设置是为了触发static final int TREEIFY_THRESHOLD = 8;属性 - 当一个桶转换为一棵树时。不是真的,因为我们还需要击中MIN_TREEIFY_CAPACITY = 64树才能出现;直到resize发生这种情况,或者桶的大小增加了一倍;因此会发生条目的重新散列。
我只能暗示为什么HashMap那句话中的文档是错误的,因为在java-8之前,bucket 没有转换为 Tree;因此,该属性将保持不变,从 java-8 开始就不再正确了。由于我不确定这一点,因此我不会将其添加为答案。
蝴蝶不菲
相关分类