Java에서 배열 다루기: 개념부터 메모리 구조까지

자바에서 배열은 동일한 데이터 타입의 여러 값을 하나의 변수로 관리할 수 있게 해주는 핵심적인 자료구조입니다. 배열을 이해하면 데이터 처리 능력이 크게 향상되며, 컬렉션 프레임워크를 학습하는 데도 기반이 됩니다.

배열의 정의와 주요 특징

배열은 동일한 타입의 요소를 순차적으로 저장하는 고정 크기의 자료구조입니다. 다음 세 가지 특성을 가집니다:

  • 동일 타입 제약: 모든 요소는 같은 데이터 타입이어야 합니다.
  • 순차적 인덱스: 각 요소는 0부터 시작하는 정수 인덱스로 접근됩니다.
  • 길이 불변성: 생성 후 크기를 변경할 수 없습니다.

배열 선언과 초기화 방법

배열은 다양한 방식으로 생성할 수 있습니다:

방법 1: 선언 후 할당

String[] names;
names = new String[3];

방법 2: 동시에 선언 및 생성

double[] scores = new double[5];

방법 3: 리터럴로 초기화

char[] vowels = new char[]{'a', 'e', 'i', 'o', 'u'};

방법 4: 축약형 리터럴 (가장 일반적)

boolean[] flags = {true, false, true};

기본값 자동 초기화

명시적 초기화 없이 배열을 생성하면, 요소들은 자동으로 기본값으로 설정됩니다:

  • 정수형 (int, long 등): 0
  • 실수형 (float, double): 0.0
  • char: '\u0000'
  • boolean: false
  • 참조형 (String, Object 등): null

요소 접근과 수정

인덱스를 사용해 특정 위치의 값을 읽거나 변경할 수 있습니다:

int[] data = {100, 200, 300};
int first = data[0];     // 값 읽기
data[1] = 999;           // 값 수정

배열 길이 확인

length 필드를 통해 배열의 크기를 얻을 수 있습니다:

int size = data.length;  // 결과: 3

배열 반복 처리

모든 요소를 순회하려면 다음과 같은 방법을 사용합니다:

전통적인 for 문

for (int i = 0; i < data.length; i++) {
    System.out.println(data[i]);
}

향상된 for 문 (enhanced for)

for (int value : data) {
    System.out.println(value);
}

while 문 활용

int idx = 0;
while (idx < data.length) {
    System.out.println(data[idx]);
    idx++;
}

메서드와 배열

배열은 매개변수나 반환값으로 전달될 수 있습니다. 다음 예제는 배열을 받아 복사본을 역순으로 만드는 메서드입니다:

public static int[] createReverseCopy(int[] source) {
    if (source == null) return null;
    
    int[] result = new int[source.length];
    for (int i = 0; i < source.length; i++) {
        result[i] = source[source.length - 1 - i];
    }
    return result;
}

public static void displayArray(int[] arr) {
    for (int val : arr) {
        System.out.print(val + " ");
    }
    System.out.println();
}

// 사용 예
int[] original = {1, 2, 3};
int[] reversed = createReverseCopy(original);
displayArray(reversed);  // 출력: 3 2 1

메모리 내 배열 저장 구조

자바에서 배열은 참조형 데이터이므로 메모리에 다음과 같이 저장됩니다:

  • 스택(stack): 배열 변수는 스택에 저장되며, 실제 객체의 메모리 주소(참조)를 포함합니다.
  • 힙(heap): 배열 객체 자체와 그 요소들은 힙 영역에 할당됩니다.

예를 들어, 아래 코드를 살펴보겠습니다:

int[] a = {10, 20};
int[] b = {30, 40};
a = b;

이 경우, a는 원래의 {10, 20} 배열을 참조하다가 b가 가리키는 {30, 40}로 참조를 변경합니다. 두 변수 모두 동일한 힙 객체를 가리키게 됩니다.

참조형 요소를 포함한 배열

배열 요소가 객체일 경우, 배열은 각 객체의 참조만 저장합니다. 다음 예제를 보세요:

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void introduce() {
        System.out.println("안녕하세요, 저는 " + name + "이고, 나이는 " + age + "세입니다.");
    }
}

// 배열 생성 및 초기화
Person[] team = new Person[2];
team[0] = new Person("김철수", 25);
team[1] = new Person("이영희", 28);

// 호출
for (Person member : team) {
    member.introduce();
}

여기서 team 배열은 힙에 존재하며, 각 요소는 별도로 생성된 Person 객체를 가리키는 참조값을 저장합니다.

자주 묻는 질문

Q: System.out.println(arr)를 하면 왜 이상한 문자열이 출력되나요?
A: 배열은 객체이므로, toString()이 오버라이딩되지 않으면 클래스명과 해시코드가 출력됩니다. 내용을 보려면 반복문이나 Arrays.toString(arr)을 사용해야 합니다.
Q: 배열 크기를 나중에 늘릴 수 있나요?
A: 불가능합니다. 크기가 유동적으로 변해야 한다면 ArrayList를 사용하세요.
Q: 배열 요소는 스택에 저장되나요?
A: 아닙니다. 배열 객체 전체가 힙에 저장되며, 스택에는 단지 참조만 있습니다.
Q: 왜 인덱스가 0부터 시작하나요?
A: 메모리 주소 계산 최적화 때문입니다. 실제 주소 = 기준주소 + (인덱스 × 데이터크기) 공식을 간단히 만들 수 있습니다.

기본형 vs 참조형 비교

특징 기본형 (Primitive) 참조형 (Reference)
저장 위치 스택 힙 (데이터), 스택 (참조)
저장 내용 실제 값 힙 주소
값 전달 방식 값 복사 참조 복사

태그: java 배열 메모리관리 참조타입 기본타입

7월 14일 04:31에 게시됨