HOWTO · Java
在 Java 中建立動態陣列
本指南教授如何在 Java 中建立動態陣列。
本頁內容
Java 陣列建立後長度固定。若要加入超出此長度的元素,可以將一般陣列包裝在 dynamic array 類別中,由類別追蹤目前存放的值數量,並在空間不足時更換底層陣列。以下範例儲存原始型別 int 值,只能在末尾新增元素、移除最後一個值,並可將儲存空間縮減至符合目前的 size。
在 Java 中使用自訂邏輯建立動態陣列
這個類別管理三項狀態:底層的 int[]、size 和 capacity。size 是目前儲存的值數量;capacity 則是底層陣列的長度。將兩者分開追蹤,陣列就能預留空間,而不會把預留槽位當成已儲存的值。
執行以下範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import java.util.Arrays;
public class DynamicArray {
private int[] values;
private int size;
public DynamicArray() {
values = new int[2];
}
public void add(int value) {
if (size == values.length) {
int newCapacity = values.length == 0 ? 1 : values.length * 2;
values = Arrays.copyOf(values, newCapacity);
}
values[size] = value;
size++;
}
public void removeLast() {
if (size == 0) {
return;
}
size--;
values[size] = 0;
}
public void shrinkToSize() {
values = Arrays.copyOf(values, size);
}
public int size() {
return size;
}
public int capacity() {
return values.length;
}
@Override
public String toString() {
return Arrays.toString(Arrays.copyOf(values, size));
}
public static void main(String[] args) {
DynamicArray numbers = new DynamicArray();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
numbers.add(50);
System.out.println(numbers + " | size=" + numbers.size()
+ " | capacity=" + numbers.capacity());
numbers.removeLast();
System.out.println(numbers + " | size=" + numbers.size()
+ " | capacity=" + numbers.capacity());
numbers.shrinkToSize();
System.out.println(numbers + " | size=" + numbers.size()
+ " | capacity=" + numbers.capacity());
}
}
輸出:
[10, 20, 30, 40, 50] | size=5 | capacity=8
[10, 20, 30, 40] | size=4 | capacity=8
[10, 20, 30, 40] | size=4 | capacity=4
新增五個值後,陣列中的值為 [10, 20, 30, 40, 50],size 為 5,capacity 為 8。呼叫 removeLast() 後,陣列中的值為 [10, 20, 30, 40],size 為 4,capacity 仍為 8。呼叫 shrinkToSize() 後,size 和 capacity 都是 4。範例輸出中的文字標籤維持英文。
了解大小、容量與調整大小
建構函式會將 capacity 設為 2、size 設為 0。每次呼叫 add 時,都會檢查 size 是否已達到 capacity。底層陣列滿了時,Arrays.copyOf 會配置一個長度加倍的新陣列,並將現有值複製過去。接著,新值會寫入索引 size 的位置,然後 size 加一。
以範例中的五次新增為例,capacity 會先從 2 增至 4,再增至 8。擴充時會複製已儲存的值;新陣列多出的槽位則可供後續新增使用。capacity 表示已配置的儲存空間,不是值的數量。toString() 方法只會複製索引小於 size 的部分,因此多出的槽位不會顯示為元素。
複製所需時間與複製的值數量成正比,而且複製期間兩個陣列都會暫時存在。容量加倍可避免每次新增都要複製,但個別新增若觸發擴充,仍須進行複製。這個小型類別用來示範運作原理;一般用途的集合通常使用 Java 的 ArrayList<Integer> 更合適。
新增與移除元素
add 只支援在末尾新增,不會在任意索引插入元素。removeLast 會將 size 減一,並把空出的槽位清為 Java 的 int 預設值 0。int 是原始型別,不是參照,因此清除槽位並非垃圾回收所必需;這麼做只是讓底層陣列未使用的部分維持可預期的狀態。當 size 為 0 時呼叫 removeLast,物件狀態不會改變。
移除元素不會自動縮減 capacity。若回收多出的陣列槽位比保留空間以供後續新增更重要,可呼叫 shrinkToSize()。縮減時也會將值複製到替換用的新陣列。若 size 為 0,capacity 會變成 0;下次呼叫 add 時,容量會先增至 1,再存入新值。此實作只儲存原始型別 int 值,且不提供索引存取、插入或移除中間元素的功能。