Dev Study/Java

[Java] 자바 배열 정리: 메모리 구조, 깊은 복사, 2차원 배열

parkhh98 2026. 1. 9. 21:07

자바 배열 학습 내용 중 핵심인 메모리 구조, 복사(Shallow vs Deep), 2차원 배열에 대해 정리함.

1. 목표 (Goal)

  • 자바 배열의 Memory 구조(Stack vs Heap)를 이해한다.
  • 얕은 복사(Shallow Copy)깊은 복사(Deep Copy)의 차이를 명확히 구분한다.
  • 2차원 배열의 선언 방식과 메모리 적재 형태를 파악한다.

2. 환경 (Environment)

  • OS: Windows 11
  • JDK: OpenJDK 17
  • IDE: VS Code

3. 개념 및 코드 분석

1) 배열의 메모리 구조

자바에서 배열은 참조 타입(Reference Type)임. 변수 자체는 Stack 영역에 생성되지만, 실제 데이터가 담긴 배열 객체는 Heap 영역에 생성됨.

int[] arr = new int[] { 10, 20, 30 };
System.out.println(arr);
System.out.println("0번 인덱스 값: " + arr[0]);
주소값이 나온다

2) 얕은 복사 (Shallow Copy)

단순 대입 연산자(=)를 사용하면 배열의 주소값만 복사됨. 이를 얕은 복사라고 함.

int[] original = { 1, 2, 3 };
int[] shallowCopy = original; // 주소값만 복사됨

shallowCopy[0] = 10; // 복사본을 수정하면

System.out.println("원본 배열: " + Arrays.toString(original));
System.out.println("복사본 배열: " + Arrays.toString(shallowCopy));
//복사본 수정시 원본도 변경된다.

하나의 객체를 두 변수가 공유하게 되므로, 의도치 않은 데이터 변경(Side Effect)이 발생할 수 있음.

원본에 영향을 끼친다

설명: 얕은 복사 후: 복사본 수정(10)이 원본에도 똑같이 반영됨 (참조 공유 Side Effect)

3) 깊은 복사 (Deep Copy)

원본과 동일한 값을 가진 새로운 객체를 Heap에 생성하려면 별도의 메서드를 사용해야 함.

방법 1: Arrays.copyOf()

// Arrays.copyOf(원본배열, 새로운길이)
int[] tmp1 = Arrays.copyOf(nums, nums.length * 2);

가장 직관적이고 많이 사용됨. 새로운 길이만큼 늘려서 복사 가능.

방법 2: System.arraycopy()

// System.arraycopy(원본, 원본시작, 타겟, 타겟시작, 길이)
System.arraycopy(nums, 0, tmp3, 0, nums.length);

성능상 이점이 있으나 파라미터가 복잡하여 가독성이 떨어질 수 있음.

int[] original = { 1, 2, 3 };
int[] deepCopy1 = Arrays.copyOf(original, original.length);
int[] deepCopy2 = new int[original.length];
System.arraycopy(original, 0, deepCopy2, 0, original.length);

deepCopy1[0] = 10;
deepCopy2[1] = 20;

System.out.println("원본 배열: " + Arrays.toString(original));
System.out.println("복사본 배열1: " + Arrays.toString(deepCopy1));
System.out.println("복사본 배열2: " + Arrays.toString(deepCopy2));

원본에 영향이 없다

4) 2차원 배열

자바의 2차원 배열은 "배열의 배열" 형태임. 1차원 배열의 각 요소가 또 다른 배열의 주소를 가지고 있음.

int[][] arr = new int[2][3];

System.out.println("arr자체를 출력: " + arr);
System.out.println("arr의 요소를 출력: " + Arrays.deepToString(arr));
System.out.println("arr[0]자체를 출력: " + arr[0]);
System.out.println("arr[0]의 요소를 출력: " + Arrays.toString(arr[0]));
System.out.println("arr[1]자체를 출력: " + arr[1]);
System.out.println("arr[1]의 요소를 출력: " + Arrays.toString(arr[1]));
System.out.println("첫번째 요소 출력: " + arr[0][0]);

2차원 배열의 다양한 출력

4. 팁: 2차원 배열 한 번에 출력하기

2차원 배열을 그냥 Arrays.toString()으로 찍으면 알 수 없는 주소값만 잔뜩 나와서 당황할 수 있음.
이럴 땐 Arrays.deepToString()을 쓰면, 내부 배열의 값까지 깔끔하게 다 보여줌!

System.out.println(Arrays.toString(arr)); // [[I@... , [I@...] (주소 출력)
System.out.println(Arrays.deepToString(arr)); // [[0, 0, 0], [0, 0, 0]] (값 출력)

 


📚 함께 보면 좋은 'Antigravity & VS Code & Java' 로드맵

배열에 대한 학습이 끝났다면, Java에 대한 기초적인 지식을 학습해보는 시간을 가져봅시다.

Next Step 절차지향과 객체지향 (원리 익히기)
[Java] 절차지향의 한계와 객체지향의 필요성