1.ArrayList擴容
默認容量是10,如果初始化時一開始指定了容量,或者通過集合作為元素,則容量為指定的大小或參數集合的大小。每次擴容為原來的1.5倍,如果新增后超過這個容量,則容量為新增后所需的最小容量。如果增加0.5倍后的新容量超過限制的容量,則用所需的最小容量與限制的容量進行判斷,超過則指定為Integer的最大值,否則指定為限制容量大小。然后通過數組的復制將原數據復制到一個更大(新的容量大小)的數組。
2.HashMap擴容
HashMap擴容可以分為三種情況:
什么時候擴容:當向容器添加元素的時候,會判斷當前容器的元素個數,如果大於等於閾值---即當前數組的長度乘以加載因子的值的時候,就要自動擴容啦。
擴容(resize)就是重新計算容量,向HashMap對象里不停的添加元素,而HashMap對象內部的數組無法裝載更多的元素時,對象就需要擴大數組的長度,以便能裝入更多的元素。當然Java里的數組是無法自動擴容的,方法是使用 一個新的數組代替已有的容量小的數組,就像我們用一個小桶裝水,如果想裝更多的水,就得換大水桶。
HashMap中的變量
首先要了解HashMap的擴容過程,我們就得了解一些HashMap中的變量:
- Node<K,V>:鏈表節點,包含了key、value、hash、next指針四個元素
- table:Node<K,V>類型的數組,里面的元素是鏈表,用於存放HashMap元素的實體
- size:記錄了放入HashMap的元素個數
- loadFactor:負載因子
- threshold:閾值,決定了HashMap何時擴容,以及擴容后的大小,一般等於table大小乘以loadFactor
HashMap的構造函數
HashMap的構造函數主要有四個,代碼如下:
- public HashMap(int initialCapacity, float loadFactor) {
- ...
- this.loadFactor = loadFactor;
- this.threshold = tableSizeFor(initialCapacity);
- }
- public HashMap(int initialCapacity) {
- this(initialCapacity, DEFAULT_LOAD_FACTOR);
- }
- public HashMap() {
- this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
- }
- public HashMap(Map<? extends K, ? extends V> m) {
- this.loadFactor = DEFAULT_LOAD_FACTOR;
- putMapEntries(m, false);
- }
其中主要有兩種形式:
- 直接拷貝別的HashMap的形式,在此不作討論
- 定義初始容量大小(table數組的大小,缺省值為16),定義負載因子(缺省值為0.75)的形式
值得注意的是,當我們自定義HashMap初始容量大小時,構造函數並非直接把我們定義的數值當做HashMap容量大小,而是把該數值當做參數調用方法tableSizeFor,然后把返回值作為HashMap的初始容量大小:
- /**
- * Returns a power of two size for the given target capacity.
- */
- 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;
- }
該方法會返回一個大於等於當前參數的2的倍數,因此HashMap中的table數組的容量大小總是2的倍數。