天天看點

Java和guava關于hashmap在初始化的時候最好給個初始容量,避免擴容引起性能問題的探究。

一般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的不對。等空了在說吧。