1차원 배열
배열은 같은 타입의 값을 정해진 길이만큼 연속된 인덱스로 관리합니다.
길이는 생성할 때 고정되며 유효한 인덱스는 0부터 length - 1까지입니다.
배열 변수에는 배열 객체 자체가 아니라 참조가 저장됩니다.
다른 변수에 대입하면 요소가 복사되는 것이 아니라 같은 배열을 함께 가리킵니다.
이 절에서는 생성, 초기화, 순회, 복사의 차이를 확인합니다.
길이와 인덱스의 경계를 구분한다
길이가 4인 배열의 마지막 인덱스는 3입니다.
index < array.length를 반복 조건으로 사용하면 빈 배열도 안전하게 처리합니다.
생성 직후에는 타입별 기본값이 들어간다
숫자는 0, boolean은 false, 참조는 null로 초기화됩니다.
기본값이 업무 의미상 유효한 값인지는 별도로 판단해야 합니다.
아래 프로그램은 생성 직후의 기본값, 원소 변경, 참조 복사를 한 흐름에서 보여 줍니다. 배열 변수와 배열 객체를 구분하면 대입 뒤 두 이름으로 같은 변화가 보이는 이유를 설명할 수 있습니다.
import java.util.Arrays;
public class ArrayCopies {
public static void main(String[] args) {
int[] original = {10, 20, 30};
int[] shared = original;
int[] copied = original.clone();
shared[0] = 99;
copied[1] = 77;
System.out.println("original=" + Arrays.toString(original));
System.out.println("shared=" + Arrays.toString(shared));
System.out.println("copied=" + Arrays.toString(copied));
// System.out.println(original[3]); // 실행 시 ArrayIndexOutOfBoundsException
}
}예제의 배열 리터럴 대신 new int[3]을 출력하면 [0, 0, 0]을 볼 수 있습니다. 이 0이 아직 값을 넣지 않았다는 뜻인지 실제 측정값 0인지 구별해야 한다면 별도의 상태나 객체 타입이 필요합니다.
original=[99, 20, 30]
shared=[99, 20, 30]
copied=[10, 77, 30]shared는 같은 배열을 가리키지만 copied는 독립 배열이므로 변경 결과가 갈라집니다.
배열 대입은 참조를 공유한다
int[] b = a 뒤에 b[0]을 바꾸면 a[0]도 바뀝니다.
독립 복사가 필요하면 clone, Arrays.copyOf, System.arraycopy를 사용합니다.
shared[0]을 바꿨을 때 original도 바뀌는 이유는 두 변수에 배열 내용이 복사된 것이 아니라 같은 배열을 가리키는 참조가 복사되었기 때문입니다. 독립된 사본이 필요하면 clone이나 Arrays.copyOf를 명시적으로 호출합니다.
int[] source = {1, 2, 3};
int[] longer = Arrays.copyOf(source, 5); // [1, 2, 3, 0, 0]
int[] range = Arrays.copyOfRange(source, 1, 3); // [2, 3]for (int index = 0; index < source.length; index++) {
source[index] *= 2;
}순회 목적에 맞는 반복문을 고른다
읽기만 하면 향상된 for가 간단하고 위치 변경이나 원소 교체가 필요하면 인덱스 for가 적합합니다.
원소 값과 인덱스를 혼동하지 않습니다.
원소의 합만 구할 때는 향상된 for를, 값을 제자리에서 바꾸거나 위치가 필요할 때는 인덱스 for를 사용해 보세요. 빈 배열과 길이 1 배열에서도 같은 순회 코드가 추가 분기 없이 동작하는지 확인하면 경계가 맞습니다.
배열 오류는 대부분 길이, 마지막 인덱스, 참조 공유를 같은 것으로 생각할 때 생깁니다.