본문 바로가기
Java

[Java] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)

by bkuk 2022. 9. 30.

얕은 복사(Shallow Copy)란?

 

 

얕은 복사로 객체가 복사된다면 실제로는 하나의 주소 값을 가지고 있으므로 하나라고 볼 수 있습니다.

여러 객체가 같은 주소를 참조하기 때문에 값을 변경해버리면 다른 대상의 값 또한 바뀌어 버리는 문제 발생합니다.

반대로 메모리 측면에서 본다면 한 객체로 할 수 있는 일은 하나로 끝내는것이 좋습니다.

객체를 복사를 했을 때 복사한 만큼 수량이 증가한다면 메모리 측면에서 본다면 비효율적이게 됩니다.

 

아래 코드는 얕은 복사에 대한 예제입니다.

package JavaStydy;

public class ShallowCopy {

	public static void main(String[] args) {

		// 얕은 복사(Shallow Copy)
		// 복사된 배열이나 원본 배열이 변경될 때 서로간의 값이 같이 변경됩니다.
		int[] a = { 1, 2, 3, 4, 5};
		int[] b = a;
		
		}
	}

}

a라는 배열을 만들었고, 인덱스 [0] ~ [4]번에 순서대로 1 ~ 5의 숫자를 할당해줬습니다.

b 배열은 a 배열을 복사했습니다.

 

 

원본 a 배열이를 복사한 b배열이 잘되었는지 확인을 위해 아래 출력문을 통해서 확인해보겠습니다.

(향상된 for문을 통해 출력했습니다.)

		System.out.println( "a 배열의 주소: " + a );
		System.out.println();
		System.out.println( "b 배열의 주소: " + b );
		System.out.println();
		
		// 향상된 for문을 통한 a배열의 인덱스 [0] ~ [4]번 확인
		System.out.println( "a 배열" );
		for( int dataA : a ) {
			System.out.print(dataA + ", ");
		}
			System.out.println("\n");
		
		// 향상된 for문을 통한 b배열의 인덱스 [0] ~ [4]번 확인
		System.out.println( "b 배열" );
		for( int dataB : b ) {
			System.out.print( dataB + ", " );

 

 

같은 주소가 나왔다는 의미는?

a와 b의 배열의 인덱스를 바꿀경우, 결과가 서로의 배열에 영향을 미친다는 의미입니다.

즉, a의 배열의 인덱스 [0] 의 값을 바꾸든, b의 배열의 인덱스 [0]의 값을 바꾸든

동일한 인덱스[0]의 값을 바꾼다는 의미입니다.

 

 

따라서 위와 같은 복사 방식은

얕은 복사라고 보면 됩니다.


 

깊은 복사(Deep Copy)란?

 

 

위와 상반되는 개념인 깊은 복사는 서로의 배열에 영향을 미치지 않는다라고 이해하시면 됩니다.

즉, 복사한 배열을 수정하더라도 원본 배열의 인덱스 값이 변경되지 않습니다.

아래 코드를 통해 확인해보겠습니다.

package JavaStydy;

public class DeepCopy {

	public static void main(String[] args) {
		
		int[] a = { 1, 2, 3, 4, 5};
		int[] b = new int[a.length];
		
		for( int i = 0; i <= (a.length-1); i++) {
			b[i] = a[i];
		}
		
            System.out.println( "a 배열의 주소: " + a );
            System.out.println();
            System.out.println( "b 배열의 주소: " + b );
            System.out.println();
	}
}

 

다른 주소값이 나왔다는 것을 확인할 수 있습니다.

 

위와 같이 for문을 통해서 깊은 복사를 하는 방식도 있지만,

자바에서는 깊은 복사에 도움을 주기위한 메서드를 제공하고 있습니다.

 

Object.clone() 메서드를 이용

public class ObjectClone_DeepCopy {

	public static void main(String[] args) {
		
		int[] a = { 1, 2, 3, 4, 5};
		int[] b = a.clone();
		
		System.out.println( "a 배열의 주소: " + a );
		System.out.println();
		System.out.println( "b 배열의 주소: " + b );
		System.out.println();
	}
}

 

 

Arrays.copyOf() 메서드를 이용

인덱스가 끝나는 범위를 지정할 수 있으며, 아래 예제는 a.length를 통해 지정할 수 있습니다.

import java.util.Arrays;

public class ArraysCopyOf_DeppCopy {

	public static void main(String[] args) {

		int[] a = { 1, 2, 3, 4, 5};
		int[] b = Arrays.copyOf(a, a.length);
		
		System.out.println( "a 배열의 주소: " + a );
		System.out.println();
		System.out.println( "b 배열의 주소: " + b );
		System.out.println();

	}

}

 

Arrays.copyOfRange() 메서드를 이용

Deep Copy를 진행할 인덱스의 시작지점과 종료지점을 지정할 수 있습니다.

import java.util.Arrays;

public class ArraysCopyOfRange_DeepCopy {

	public static void main(String[] args) {
		
		int[] a = { 1, 2, 3, 4, 5};
		int[] b = Arrays.copyOfRange(a, 0, 2);
		
		System.out.println( "a 배열의 주소: " + a );
		System.out.println();
		System.out.println( "b 배열의 주소: " + b );
		System.out.println();
		
		for( int data : b ) {
			System.out.println(data);
		}
	}
}

 

 

System.arraycopy() 메서드를 이용

설정한 인덱스를 복사 대상인 배열의 지정 인덱스로 복사합니다.

public class SystemArrayCopy_DeepCopy {

	public static void main(String[] args) {
		
		int[] a = { 1, 2, 3, 4, 5};
		int[] b = { 0, 0, 0, 0, 0};
		
		System.out.print( "배열 b의 복사 전 value : ");
		for( int BeforData : b ) {
			System.out.print( BeforData );
		}
		
		System.out.println();
		System.out.println( "\n" + "System.arraycopy(a, 0, b, 3, 2); 라고 적었습니다. ");
		System.out.println( "위 실행문의 의미는 a 배열의 인덱스 0번을 기준으로 2개만, b 배열의 인덱스 3번부터 복사하겠다는 뜻 " +  "\n");
		System.arraycopy(a, 0, b, 3, 2);
		
		System.out.print( "배열 b의 복사 후 value : ");
		for( int AfterData : b ) {
			System.out.print( AfterData );
		}
	}
}

 

코딩팩토리님의  [Java] 자바 배열을 복사하는 다양한 방법 (깊은복사, 얕은복사)을 참고해서 작성했습니다.

주소: https://coding-factory.tistory.com/548?category=758267 

댓글