본문 바로가기

Java

[ 자바 / Java ] 얕은복사 vs 깊은복사 (shallow copy /deep copy) 배열 (part2)

https://mundol-colynn.tistory.com/127

 

[JAVA / 자바] 배열1

배열이란? Java에서 배열(Array)은 동일한 데이터 타입의 여러 원소(element)들을 저장하는 자료 구조입니다. 배열은 같은 유형의 변수를 담을 수 있는 고정 크기의 데이터 구조로, 원소는 메모리에

mundol-colynn.tistory.com

 

지난 포스팅에 이어서, 자바 배열의 복사에 대해서 알아보겠습니다.

Java에서 배열의 복사는 크게 얕은 복사(shallow copy)와 깊은 복사(deep copy) 두 가지 방법이 있습니다.

 

얕은 복사(shallow copy)

배열의 주소 값을 복사하여 새로운 배열을 생성하는 방식입니다.

주소값을 새로 생성한 것이 아니라 "복사하여" 가져온 것이므로, 새로운 배열과 원본 배열은 같은 객체를 참조하며, 한 쪽에서 값을 변경하면 다른 쪽에서도 변경이 반영됩니다.

// int형 배열 originArray선언 
int[] originalArray = {1, 2, 3, 4, 5};

// 또 다른 int형 배열 copiedArray에 originArray의 주소값을 대입 
int[] copiedArray = originalArray;  // 얕은 복사

System.out.println("originalArray[2]: " + originalArray[2]);  // 출력: 3
System.out.println("copiedArray[2]: " + copiedArray[2]);      // 출력: 3

copiedArray[2] = 10;

System.out.println("originalArray[2]: " + originalArray[2]);  // 출력: 10
System.out.println("copiedArray[2]: " + copiedArray[2]);      // 출력: 10

위의 코드에서 arr1 배열 변수의 주소 값을 arr2에 복사하여 같은 배열 객체를 참조하도록 하였습니다.

그리고 arr2 배열의 0번 인덱스 값을 변경하였고, 이후에 arr1 배열의 0번 인덱스 값을 출력해보았습니다. 결과적으로 출력 결과는 4가 됩니다.

 

 

깊은 복사(deep copy)

배열의 각 요소의 값을 복사하여 새로운 배열을 "생성"하는 방식입니다. 따라서 새로운 배열과 원본 배열은 서로 다른 객체를 참조하며, 한 쪽에서 값을 변경하더라도 다른 쪽에서는 변경이 반영되지 않습니다

 

자바 1차원 배열의 깊은 복사는 배열의 각 요소들을 새로운 배열에 복사하는 것을 의미합니다. 이때, 각 요소를 복사할 때 원본 배열의 값을 그대로 복사하는 것이 아니라, 새로운 메모리 공간을 할당하여 값을 복사합니다. 따라서 깊은 복사를 통해 새로운 배열을 생성하면, 원본 배열과 새로운 배열이 완전히 분리되어 각자의 메모리 공간을 사용하게 됩니다.

예를 들어, 다음과 같이 정수형 1차원 배열을 생성하고, 이 배열을 깊은 복사하여 새로운 배열을 생성하는 코드를 작성해보겠습니다.

 

 

 

int[] originalArray = {1, 2, 3, 4, 5};
int[] copiedArray = new int[originalArray.length];

for (int i = 0; i < originalArray.length; i++) {
    copiedArray[i] = originalArray[i];
}

위 코드에서, 원본 배열 originalArray의 길이만큼 새로운 배열 copiedArray를 생성합니다. 그리고 for문을 이용하여 원본 배열의 각 요소를 새로운 배열에 복사합니다. 이때, originalArray[i]의 값을 그대로 대입하는 것이 아니라, copiedArray[i]에 새로운 메모리 공간을 할당하여 값을 복사합니다. 따라서 originalArraycopiedArray는 완전히 독립적인 배열로 동작하게 됩니다.

 

깊은복사 방법 3가지

 

1. for문을 이용한 깊은 복사

가장 기본적인 방법으로, for문을 이용하여 원본 배열의 각 요소를 새로운 배열에 복사하는 방식입니다. 예를 들어, int형 배열 arr1을 깊은 복사하여 arr2에 저장하고자 할 경우 아래와 같은 코드를 작성할 수 있습니다.

 

int[] arr1 = {1, 2, 3};
int[] arr2 = new int[arr1.length];

for (int i = 0; i < arr1.length; i++) {
    arr2[i]
}

 

 

2. Arrays 클래스의 copyOf 메소드를 이용한 깊은 복사

Java에서는 Arrays 클래스의 copyOf 메소드를 이용하여 배열의 복사를 수행할 수 있습니다.

 -> java.util.Arrays 를 import하여 사용합니다.

copyOf 메소드는 원본 배열의 일부 또는 전체를 새로운 배열에 복사하는 기능을 제공합니다. 예를 들어, 위에서 사용한 int형 배열 arr1을 깊은 복사하여 arr2에 저장하고자 할 경우 아래와 같은 코드를 작성할 수 있습니다.

 

int[] arr1 = {1, 2, 3};
int[] arr2 = Arrays.copyOf(arr1, arr1.length);

 

 

3. System 클래스의 arraycopy 메소드를 이용한 깊은 복사

System 클래스의 arraycopy 메소드를 이용하여 배열의 복사를 수행할 수도 있습니다.

   -> System클래스는 java.lang 패키지에 속해 있기 때문에, 다른 패키지에서 import 없이도 기본적으로 사용 가능합니다.

arraycopy 메소드는 원본 배열의 일부 또는 전체를 새로운 배열에 복사하는 기능을 제공합니다. 예를 들어, 위에서 사용한 int형 배열 arr1을 깊은 복사하여 arr2에 저장하고자 할 경우 아래와 같은 코드를 작성할 수 있습니다.

int[] arr1 = {1, 2, 3};
int[] arr2 = new int[arr1.length];
System.arraycopy(arr1, 0, arr2, 0, arr1.length);

위의 세 가지 방법 모두 깊은 복사를 수행할 수 있지만, 배열의 크기가 작을 경우에는 성능 차이가 크게 나타나지 않습니다. 따라서 복사할 배열의 크기와 상황에 따라 가장 적절한 방법을 선택하여 사용하는 것이 좋습니다.

 

 

 

 

 

Java에서 깊은 복사와 얕은 복사는 각각 다른 상황에서 사용할 수 있습니다.

얕은 복사는 복사된 배열과 원래 배열이 같은 메모리 주소를 공유하므로, 복사된 배열의 요소를 변경하면 원래 배열의 요소도 변경됩니다. 이 경우, 원래 배열을 보호하면서 복사본에서 배열 요소를 읽기만 할 필요가 있을 때 사용됩니다.

반면에 깊은 복사는 복사된 배열과 원래 배열이 서로 다른 메모리 주소를 가지므로, 복사본에서 배열 요소를 변경하더라도 원래 배열의 요소는 변경되지 않습니다. 이 경우, 원래 배열을 보호하면서 복사본에서 배열 요소를 자유롭게 변경할 필요가 있을 때 사용됩니다.

따라서, 만약 배열 요소를 변경해도 원래 배열이 변경되어도 상관없는 경우에는 얕은 복사를 사용하고, 원래 배열을 보호하면서 복사본에서 배열 요소를 자유롭게 변경해야 하는 경우에는 깊은 복사를 사용합니다.

 

 

Reference

  1. https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
  2. https://www.baeldung.com/java-deep-copy
  3. https://www.geeksforgeeks.org/array-copy-in-java/
  4. https://stackoverflow.com/questions/10805293/why-is-the-arrays-class-imported-by-default-when-a-java-file-is-compiled