자바 배열 학습 내용 중 핵심인 메모리 구조, 복사(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] 절차지향의 한계와 객체지향의 필요성
'Dev Study > Java' 카테고리의 다른 글
| [Java] 다형성과 추상 클래스: if문의 늪에서 탈출하기 (3) | 2026.01.21 |
|---|---|
| [Java] 책임은 누구에게 있는가: 상속과 super의 본질 (0) | 2026.01.21 |
| [Java] 객체지향 설계와 메모리 구조: 싱글턴, 빌더 패턴, 그리고 불변성 (0) | 2026.01.15 |
| [Java] 절차지향의 한계와 객체지향의 필요성 (5) | 2026.01.12 |
| [Java] 변수, 연산자, 그리고 제어문 (0) | 2026.01.06 |



