一、內部數組大小與初始容量的關係
1、什麼是初始容量?
初始容量指的是ArrayList在創建時分配的內部數組大小,也就是能夠存儲元素的空間大小。通常情況下我們使用不帶參數的構造方法來創建ArrayList,這種情況下,初始容量為10。但是,如果我們有提前知道ArrayList中會存儲的元素數量,那麼在創建時可以通過傳入一個整數值來指定初始容量。這樣,初始化時就能夠自動設置內部數組的大小。
2、內部數組的實際大小是多少?
除非使用帶有參數構造函數來指定初始容量,否則ArrayList的內部數組大小始終為10。但是,這個初始容量只是初始值,實際上ArrayList會自動擴容。
3、什麼時候會觸發自動擴容?
當我們往ArrayList中添加超出容量的元素時,就會觸發ArrayList自動擴容。具體來說,它會把當前的內部數組複製到一個更大的數組中,然後繼續添加新元素。
// 通過構造函數指定初始容量
ArrayList list = new ArrayList(20);
// 內部數組大小是多少?
System.out.println(list.size()); // 輸出 0
二、初始容量與性能的關係
1、為什麼初始容量重要?
初始容量實際上在ArrayList的性能中扮演著重要的角色。不同的初始容量會影響到ArrayList的性能表現。如果初始容量太小,ArrayList就會頻繁地進行擴容操作,影響效率。而如果初始容量太大,將導致內存浪費。
2、如何確定合適的初始容量?
為了避免頻繁擴容,我們需要給出一個合適的初始容量。通常,初始容量應該儘可能地接近預期的元素個數以減少內存浪費。一般來說,我們可以通過創建一個稍大於實際元素個數的ArrayList,然後調整其初始容量來實現優化。
3、通過代碼測試ArrayList在不同初始容量下的性能:
// 不同的初始容量對添加性能的影響
int size = 1000000;
long start = System.currentTimeMillis();
ArrayList list1 = new ArrayList(size);
for (int i = 0; i < size; i++) {
list1.add(i);
}
long end = System.currentTimeMillis();
System.out.println("指定初始容量:" + (end - start) + " 毫秒");
start = System.currentTimeMillis();
ArrayList list2 = new ArrayList();
for (int i = 0; i < size; i++) {
list2.add(i);
}
end = System.currentTimeMillis();
System.out.println("未指定初始容量:" + (end - start) + " 毫秒");
三、初始容量調整的實現原理
1、如何調整初始容量?
調整初始容量的核心方法是ensureCapacity()
,通過調用這個方法來設置ArrayList的實際容量。如果我們知道ArrayList中需要多少元素,可以在創建之時指定容量。否則,在添加元素時,每當容量不足時,ArrayList就會自動增加一個「增量」來調整容量。默認情況下,「增量」是當前容量的一半。
2、如何自定義「增量」?
我們可以通過設置ArrayList(int initialCapacity)
構造方法中的增量參數來自定義「增量」值。如果我們希望增量增加一倍或者減半,那麼只需在創建ArrayList對象時傳遞一個新的增量參數即可。
3、添加元素時自動調整容量的實現原理:
// 添加元素時自動增加容量的實現原理
private static final int DEFAULT_CAPACITY = 10;
private Object[] elementData;
private int size;
private void ensureCapacity(int capacity) {
if (capacity > elementData.length) {
// 計算新長度
int newCapacity = elementData.length + (elementData.length >> 1);
// 如果擴增容量還是不夠,就直接擴大容量到需要的大小
if (newCapacity < capacity) {
newCapacity = capacity;
}
// 複製原數組
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
public boolean add(E e) {
// 添加元素時自動擴容
ensureCapacity(size + 1);
elementData[size] = e;
size++;
return true;
}
四、初始容量與內存開銷的關係
1、如何減少內存開銷?
隨著初始容量的增大,ArrayList佔用的內存空間也會增多。因此,如果我們想要降低內存開銷,就需要儘可能地減少初始容量。
2、如何查看ArrayList佔用的內存空間?
我們可以通過在Java應用程序中使用JProfiler等內存分析工具來查看ArrayList實例佔用的內存空間。
3、代碼示例:如何比較不同初始容量的內存佔用情況:
// 不同初始容量下內存佔用的差異
Runtime runtime = Runtime.getRuntime();
long usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();
ArrayList list = new ArrayList();
for (int i = 0; i < 100000; i++) {
list.add("Element " + i);
}
long usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();
System.out.println("內存佔用:" + (usedMemoryAfter - usedMemoryBefore) + " bytes");
usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();
list = new ArrayList(100000);
for (int i = 0; i < 100000; i++) {
list.add("Element " + i);
}
usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();
System.out.println("內存佔用:" + (usedMemoryAfter - usedMemoryBefore) + " bytes");
五、總結
本文從各個方面深入闡述了ArrayList的初始容量問題,包括內部數組大小與初始容量的關係、初始容量與性能的關係、初始容量調整的實現原理、初始容量與內存開銷的關係。通過深入研究ArrayList的初始容量問題,我們可以更好地使用它,避免無謂的內存浪費,優化程序性能。
原創文章,作者:TNHOT,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/329021.html