一般Java的集合初始化如下帶初始容量的map:
Map map = new HashMap(4);
本意是希望給HashMap設定初始值, 避免擴容(resize)的開銷. 但是沒有考慮當添加的元素數量達到HashMap容量的75%時将出現resize.
是以說上面的是徒勞的。錯誤的。
guava裡面有工具類Maps,可以很友善的建立一個集合,并且,帶上合适的大小初始化值。具體如下:
Map<String, Object> map = Maps.newHashMapWithExpectedSize(7);
二者的詳細對比如下:
//實際上map的配置設定大小是根據 7/(0.75) + 1 = 10 去配置設定大小的;
//則當元素添加到7個;是以不會觸發resize();
Map<String, Object> map = Maps.newHashMapWithExpectedSize(7);
public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {
return new HashMap<K, V>(capacity(expectedSize));
}
static int capacity(int expectedSize) {//expectedSize = 7;這傳進去個7,傳回的是10;
if (expectedSize < 3) {
checkNonnegative(expectedSize, "expectedSize");
return expectedSize + 1;
}
if (expectedSize < Ints.MAX_POWER_OF_TWO) { //MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2); //Integer.SIZE = 32;
// 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; int類型的最大值啦;二進制 就是31個1的數字。
}
public HashMap(int initialCapacity) {//這傳入的initialCapacity = 10;
this(initialCapacity, DEFAULT_LOAD_FACTOR); //static final float DEFAULT_LOAD_FACTOR = 0.75f;
}
//Java 1.7是如下算法:結果算出來是capacity = 16;
int capacity = 1;
while (capacity < initialCapacity)//initialCapacity = 10 傳進來的
capacity <<= 1;
threshold = (int) (capacity * loadFactor);//loadFactor = 0.75 預設的,這個擴容極限值是16 * 0.75 = 12即threshold = 12;
//什麼時候resize
//在添加一個元素即addEntry()的時候有如下判斷
if (size++ >= threshold)
resize(2 * table.length);
//Java 1.8是如下算法:結果算出來是16;額,我是debug看到的是16,下面的移來移去的,看不懂。
this.threshold = tableSizeFor(initialCapacity);//initialCapacity = 10;穿進去是10,傳回的是16;
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
//什麼時候resize
//在添加一個元素即putVal()的時候有如下判斷
if (++size > threshold)// 我debug的時候,看到這個threshold變成12啦,不知道什麼時候,16變12啦;
resize();
//為什麼呢,不是應該在resize方法裡面重置大小之後再修改這個門檻值的嗎。具體的不知道哪裡被修改啦,還是說我的debug的不對。等空了在說吧。