HOWTO · Java
Java에서 동적 배열 만들기
이 가이드에서는 Java에서 동적 배열을 만드는 방법을 설명합니다.
이 페이지의 내용
Java 배열은 만든 뒤 길이를 바꿀 수 없습니다. 그 길이보다 많은 요소를 추가하려면 일반 배열을 감싸는 동적 배열 클래스를 만들고, 저장된 값의 개수를 추적하며 공간이 부족할 때 내부 배열을 더 큰 배열로 교체하면 됩니다. 아래 예제는 기본형 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]이 들어 있고, 크기는 5, 용량은 8입니다. removeLast()를 호출한 뒤에는 [10, 20, 30, 40]이 남으며, 크기는 4, 용량은 8입니다. shrinkToSize()를 호출하면 크기와 용량이 모두 4가 됩니다.
크기, 용량 및 크기 조정 이해하기
생성자는 용량을 2, 크기를 0으로 시작합니다. add를 호출할 때마다 크기가 용량에 도달했는지 확인합니다. 내부 배열이 가득 차면 Arrays.copyOf가 길이가 두 배인 새 배열을 할당하고 기존 값을 복사합니다. 그런 다음 다음 값을 size 인덱스에 기록하고 크기를 1 늘립니다.
예제에서 값을 다섯 번 추가하면 용량은 2에서 4로, 다시 8로 바뀝니다. 용량을 늘리는 과정에서 저장된 값이 복사되고, 새 배열의 남는 칸은 이후 추가 작업에 사용할 수 있습니다. 용량은 할당된 저장 공간을 나타내며, 값의 개수를 뜻하지 않습니다. toString() 메서드는 크기 이전의 부분만 복사하므로 남는 칸은 요소로 표시되지 않습니다.
복사에 걸리는 시간은 복사하는 값의 개수에 비례하며, 복사 중에는 두 배열이 일시적으로 모두 메모리에 있어야 합니다. 용량을 두 배씩 늘리면 추가할 때마다 복사하지 않아도 되지만, 용량을 늘려야 하는 개별 추가 작업에서는 여전히 복사가 발생합니다. 이 작은 클래스는 동작 원리를 보여 주기 위한 예제입니다. 일반적인 컬렉션에는 보통 Java의 ArrayList<Integer>가 더 적합합니다.
요소 추가 및 제거
add는 끝에 값을 추가하는 기능만 지원하며, 임의의 인덱스에 삽입하지는 않습니다. removeLast는 크기를 1 줄이고, 비워진 칸을 Java의 기본 int 값인 0으로 설정합니다. int는 참조가 아니라 기본형 값이므로, 이 칸을 지워도 가비지 컬렉션에는 영향을 주지 않습니다. 대신 내부 배열의 미사용 부분을 예측 가능한 상태로 유지합니다. 크기가 0일 때 removeLast를 호출하면 객체의 상태는 바뀌지 않습니다.
제거해도 용량은 자동으로 줄어들지 않습니다. 앞으로 추가할 공간을 남겨 두는 것보다 배열의 여유 칸을 회수하는 일이 더 중요할 때 shrinkToSize()를 호출하세요. 이 메서드도 값을 새 배열로 복사합니다. 크기가 0이면 용량은 0이 되고, 다음에 add를 호출하면 새 값을 저장하기 전에 용량을 1로 늘립니다. 이 구현은 기본형 int 값만 저장하며 인덱스 접근, 삽입, 중간 요소 제거 기능은 제공하지 않습니다.