ArrayList:
-------------------------------------
明確知道容量:直接設置初始容量,如new ArrayList<>(100)
無法確定容量:預估一個比較接近的值,如果實在無法確定,則無需指定初始值 (有默認值)
ArrayList沒有加載因子,初始容量10,擴容增量為原來的0.5倍取整
HashMap(HashSet規則相同)
-------------------------------------
HashMap的默認加載因子為0.75,但可以使用構造器指定,如new HashMap<>(100, 1),此時指定加載因子為1
故計算HashMap的初始值時的工式為:(int) (realSize / loadFactor) + 1
如果實際容量為100,加載因子為默認(0.75),計算容量為:(int) (100 / 0.75) + 1 = 134,則實例化HashMap為 new HashMap<>(134) (注意:由於HashMap的容量必須為2的N次方,故此時HashMap的實際容量為256)
如果實際容量為100,加載因子1,則計算工式為:(int) (100 / 1) + 1 = 101,則則實例化HashMap為 new HashMap<>(101, 1) (注意:由於HashMap的容量必須為2的N次方,故此時HashMap的實際容量為128)
HashMap、HashMap加載因子0.75,初始容量16,擴容增量為原來的1倍
注意:加載因子越大節省內存但查找效率低,加載因子越小耗內存但查找效率高,系統默認加載因子為0.75,一般情況下我們是無需修改的。
//以下為計算HashMap的實際容量 //計算容量。 int capacity = (int) (realSize / loadFactor) + 1; //必須為2的N次方並進行上舍入。 int pow = (int)Math.ceil( Math.log(capacity) / Math.log(2.0)); //返回2的N次方為實際容量。 return (int) Math.pow(2, pow);
以上單元測試HashMap、ArrayList持續增加元素及擴容情況:
@Test public void testHashMapResize() throws Exception { System.out.println("-------- 開始測試HashMap --------"); System.out.println("不設置 initCapacity"); this.testHashMapResizeProfile(0); System.out.println(""); System.out.println("initCapacity 為 25"); this.testHashMapResizeProfile(25); System.out.println(""); System.out.println("initCapacity 為 34"); this.testHashMapResizeProfile(34); System.out.println(); System.out.println("-------- 開始測試ArrayList --------"); System.out.println("不設置 initCapacity"); this.testArrayListResizeProfile(0); System.out.println(""); System.out.println("initCapacity 為 25"); this.testArrayListResizeProfile(25); } /** * 以循環添加25個元素測試擴容。 * @param initCapacity 初始容量 * @throws Exception */ private void testHashMapResizeProfile(int initCapacity) throws Exception { Map<String, String> map = null; if (initCapacity <= 0) { map = new HashMap(); } else { map = new HashMap(initCapacity); } Field threshold = map.getClass().getDeclaredField("threshold"); Field size = map.getClass().getDeclaredField("size"); Method capacity = map.getClass().getDeclaredMethod("capacity"); threshold.setAccessible(true); size.setAccessible(true); capacity.setAccessible(true); // 臨界值、容量測試 for (int i = 1; i <= 25; i++) { map.put(String.valueOf(i), i + "**"); System.out.println("第" + i + "個對象, size為" + size.get(map) + ", threshold為" + threshold.get(map) + ", capacity容量為" + capacity.invoke(map)); } } /** * 以循環添加25個元素測試擴容。 * @param initCapacity 初始容量 * @throws Exception */ private void testArrayListResizeProfile(int initCapacity) throws Exception { ArrayList<String> list = null; if (initCapacity <= 0) { list = new ArrayList(); } else { list = new ArrayList(initCapacity); } Field size = list.getClass().getDeclaredField("size"); Field elementData = list.getClass().getDeclaredField("elementData"); size.setAccessible(true); elementData.setAccessible(true); // 臨界值、容量測試 for (int i = 1; i <= 25; i++) { list.add(String.valueOf(i)); System.out.println("第" + i + "個對象, size為:" + size.get(list) + ", 擴容后容量為:" + ((Object[])elementData.get(list)).length); } }
以下為HashMap持續增加元素及擴容輸出:
不設置 initCapacity 第1個對象, size為1, threshold為12, capacity容量為16 第2個對象, size為2, threshold為12, capacity容量為16 第3個對象, size為3, threshold為12, capacity容量為16 第4個對象, size為4, threshold為12, capacity容量為16 第5個對象, size為5, threshold為12, capacity容量為16 第6個對象, size為6, threshold為12, capacity容量為16 第7個對象, size為7, threshold為12, capacity容量為16 第8個對象, size為8, threshold為12, capacity容量為16 第9個對象, size為9, threshold為12, capacity容量為16 第10個對象, size為10, threshold為12, capacity容量為16 第11個對象, size為11, threshold為12, capacity容量為16 第12個對象, size為12, threshold為12, capacity容量為16 第13個對象, size為13, threshold為24, capacity容量為32 第14個對象, size為14, threshold為24, capacity容量為32 第15個對象, size為15, threshold為24, capacity容量為32 第16個對象, size為16, threshold為24, capacity容量為32 第17個對象, size為17, threshold為24, capacity容量為32 第18個對象, size為18, threshold為24, capacity容量為32 第19個對象, size為19, threshold為24, capacity容量為32 第20個對象, size為20, threshold為24, capacity容量為32 第21個對象, size為21, threshold為24, capacity容量為32 第22個對象, size為22, threshold為24, capacity容量為32 第23個對象, size為23, threshold為24, capacity容量為32 第24個對象, size為24, threshold為24, capacity容量為32 第25個對象, size為25, threshold為48, capacity容量為64 注意:擴容2次 initCapacity 為 25 第1個對象, size為1, threshold為24, capacity容量為32 第2個對象, size為2, threshold為24, capacity容量為32 第3個對象, size為3, threshold為24, capacity容量為32 第4個對象, size為4, threshold為24, capacity容量為32 第5個對象, size為5, threshold為24, capacity容量為32 第6個對象, size為6, threshold為24, capacity容量為32 第7個對象, size為7, threshold為24, capacity容量為32 第8個對象, size為8, threshold為24, capacity容量為32 第9個對象, size為9, threshold為24, capacity容量為32 第10個對象, size為10, threshold為24, capacity容量為32 第11個對象, size為11, threshold為24, capacity容量為32 第12個對象, size為12, threshold為24, capacity容量為32 第13個對象, size為13, threshold為24, capacity容量為32 第14個對象, size為14, threshold為24, capacity容量為32 第15個對象, size為15, threshold為24, capacity容量為32 第16個對象, size為16, threshold為24, capacity容量為32 第17個對象, size為17, threshold為24, capacity容量為32 第18個對象, size為18, threshold為24, capacity容量為32 第19個對象, size為19, threshold為24, capacity容量為32 第20個對象, size為20, threshold為24, capacity容量為32 第21個對象, size為21, threshold為24, capacity容量為32 第22個對象, size為22, threshold為24, capacity容量為32 第23個對象, size為23, threshold為24, capacity容量為32 第24個對象, size為24, threshold為24, capacity容量為32 第25個對象, size為25, threshold為48, capacity容量為64 注意:擴容1次 initCapacity 為 34 (int) (25 / 0.75) + 1 = 34 第1個對象, size為1, threshold為48, capacity容量為64 第2個對象, size為2, threshold為48, capacity容量為64 第3個對象, size為3, threshold為48, capacity容量為64 第4個對象, size為4, threshold為48, capacity容量為64 第5個對象, size為5, threshold為48, capacity容量為64 第6個對象, size為6, threshold為48, capacity容量為64 第7個對象, size為7, threshold為48, capacity容量為64 第8個對象, size為8, threshold為48, capacity容量為64 第9個對象, size為9, threshold為48, capacity容量為64 第10個對象, size為10, threshold為48, capacity容量為64 第11個對象, size為11, threshold為48, capacity容量為64 第12個對象, size為12, threshold為48, capacity容量為64 第13個對象, size為13, threshold為48, capacity容量為64 第14個對象, size為14, threshold為48, capacity容量為64 第15個對象, size為15, threshold為48, capacity容量為64 第16個對象, size為16, threshold為48, capacity容量為64 第17個對象, size為17, threshold為48, capacity容量為64 第18個對象, size為18, threshold為48, capacity容量為64 第19個對象, size為19, threshold為48, capacity容量為64 第20個對象, size為20, threshold為48, capacity容量為64 第21個對象, size為21, threshold為48, capacity容量為64 第22個對象, size為22, threshold為48, capacity容量為64 第23個對象, size為23, threshold為48, capacity容量為64 第24個對象, size為24, threshold為48, capacity容量為64 第25個對象, size為25, threshold為48, capacity容量為64 注意:未擴容
以下為ArrayList持續增加元素及擴容輸出:
不設置 initCapacity
第1個對象, size為:1, 擴容后容量為:10
第2個對象, size為:2, 擴容后容量為:10
第3個對象, size為:3, 擴容后容量為:10
第4個對象, size為:4, 擴容后容量為:10
第5個對象, size為:5, 擴容后容量為:10
第6個對象, size為:6, 擴容后容量為:10
第7個對象, size為:7, 擴容后容量為:10
第8個對象, size為:8, 擴容后容量為:10
第9個對象, size為:9, 擴容后容量為:10
第10個對象, size為:10, 擴容后容量為:10
第11個對象, size為:11, 擴容后容量為:15
第12個對象, size為:12, 擴容后容量為:15
第13個對象, size為:13, 擴容后容量為:15
第14個對象, size為:14, 擴容后容量為:15
第15個對象, size為:15, 擴容后容量為:15
第16個對象, size為:16, 擴容后容量為:22
第17個對象, size為:17, 擴容后容量為:22
第18個對象, size為:18, 擴容后容量為:22
第19個對象, size為:19, 擴容后容量為:22
第20個對象, size為:20, 擴容后容量為:22
第21個對象, size為:21, 擴容后容量為:22
第22個對象, size為:22, 擴容后容量為:22
第23個對象, size為:23, 擴容后容量為:33
第24個對象, size為:24, 擴容后容量為:33
第25個對象, size為:25, 擴容后容量為:33
注意:擴容2次
initCapacity 為 25
第1個對象, size為:1, 擴容后容量為:25
第2個對象, size為:2, 擴容后容量為:25
第3個對象, size為:3, 擴容后容量為:25
第4個對象, size為:4, 擴容后容量為:25
第5個對象, size為:5, 擴容后容量為:25
第6個對象, size為:6, 擴容后容量為:25
第7個對象, size為:7, 擴容后容量為:25
第8個對象, size為:8, 擴容后容量為:25
第9個對象, size為:9, 擴容后容量為:25
第10個對象, size為:10, 擴容后容量為:25
第11個對象, size為:11, 擴容后容量為:25
第12個對象, size為:12, 擴容后容量為:25
第13個對象, size為:13, 擴容后容量為:25
第14個對象, size為:14, 擴容后容量為:25
第15個對象, size為:15, 擴容后容量為:25
第16個對象, size為:16, 擴容后容量為:25
第17個對象, size為:17, 擴容后容量為:25
第18個對象, size為:18, 擴容后容量為:25
第19個對象, size為:19, 擴容后容量為:25
第20個對象, size為:20, 擴容后容量為:25
第21個對象, size為:21, 擴容后容量為:25
第22個對象, size為:22, 擴容后容量為:25
第23個對象, size為:23, 擴容后容量為:25
第24個對象, size為:24, 擴容后容量為:25
第25個對象, size為:25, 擴容后容量為:25
注意:沒有擴容