본문 바로가기
Java/Java

배열) 얕은 복사, 깊은 복사

by 박채니 2022. 3. 9.

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


배열의 복사는 크게 얕은 복사와 깊은 복사로 나뉘어집니다.

배열의 복사에 대해서 알아보겠습니다.


☞ 얕은 복사 (shallow copy)

- 객체 주소값을 복사 (스택 영역의 값 복사)

- 같은 객체를 공유

 

public void test1() {
	char[] arr1 = new char[] {'a', 'b', 'c'};
	char[] arr2 = arr1;	//참조주소값 복사(스택메모리)
		
	for(int i = 0; i < arr1.length; i++) {
		System.out.println("arr1 : " + arr1[i] + " / arr2 : " + arr2[i]);
	}
	System.out.println("arr1 : " + arr1.hashCode() + " , arr2 : " + arr2.hashCode());
}

@콘솔출력값
arr1 : a / arr2 : a
arr1 : b / arr2 : b
arr1 : c / arr2 : c
arr1 : 1227229563 , arr2 : 1227229563

arr2에 arr1을 대입(복사) 하고 각 인덱스 별 값과 해쉬코드를 출력해보았습니다.

스택 메모리의 주소값을 그대로 가져와 복사했기 때문에 같은 객체를 공유하게 됩니다.

같은 객체를 공유하기 때문에 하나의 값을 바꾸면 값이 모두 변경됩니다.

 

arr1[1] = 'f';

for(int i = 0; i < arr1.length; i++) {
	System.out.println("arr1 : " + arr1[i] + " / arr2 : " + arr2[i]);
}

@콘솔출력값
arr1 : a / arr2 : a
arr1 : f / arr2 : f
arr1 : c / arr2 : c

arr1[1]만 'f'로 변경했는데 arr2[1]도 동일하게 'f'로 변경된 것을 볼 수 있습니다.

 

 

☞ 깊은 복사 (deep copy)

- 배열 객체를 복사 (힙 영역을 복사)

- 동일한 값을 가진 배열 객체가 2개가 되는 것

 

① 직접 값 대입하여 복사

public void test2() {
	int[] arr1 = new int[] {10, 20, 30};
	int[] arr2 = new int[arr1.length];
		
	for(int i = 0; i < arr1.length; i++) {
		arr2[i] = arr1[i];	//값 복사
	}
		
	//값 출력
	for(int i = 0; i < arr1.length; i++) {
		System.out.println("arr1 : " + arr1[i] + " / arr2 : " + arr2[i]);
	}
	System.out.println("arr1 : " + arr1.hashCode() + " , arr2 : " + arr2.hashCode());
}

@콘솔출력값
arr1 : 10 / arr2 : 10
arr1 : 20 / arr2 : 20
arr1 : 30 / arr2 : 30
arr1 : 1227229563 , arr2 : 1982791261

arr2라는 객체 생성 후 직접 값을 대입하여 복사하였습니다.

동일한 값을 갖고 있지만, 이 둘은 서로 다른 객체를 공유하고 있으므로 해쉬코드 값이 상이합니다.

서로 다른 객체와 주소값을 갖고 있으므로 하나의 값을 변경해도 복사한 객체에는 아무런 변화가 없습니다.

 

arr1[1] = 50;
		
for(int i = 0; i < arr1.length; i++) {
	System.out.println("arr1 : " + arr1[i] + " / arr2 : " + arr2[i]);
}

@콘솔출력값
arr1 : 10 / arr2 : 10
arr1 : 50 / arr2 : 20
arr1 : 30 / arr2 : 30

원본 arr1[1]을 50으로 변경해도 복사한 arr2[1]의 값은 그대로 인 것을 볼 수 있습니다.

 

② System.arraycopy (static 메소드 → 객체 생성 X)

public void test3() {
	double[] dArr1 = new double[] {3.3, 5.0, 2.6};
	double[] dArr2 = new double[dArr1.length];
		
	//void java.lang.System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
	//darr1의 0번째부터 darr1.length길이만큼 darr2의 0번째부터 복사하여 대입해줘~
	System.arraycopy(dArr1, 0, dArr2, 0, dArr1.length);
		
	for(int i = 0; i < dArr1.length; i++) {
		System.out.println("dArr1 : " + dArr1[i] + " / dArr2 : " + dArr2[i]);
	}
	System.out.println("dArr1 : " + dArr1.hashCode() + " , dArr2 : " + dArr2.hashCode());
}

@콘솔출력값
dArr1 : 3.3 / dArr2 : 3.3
dArr1 : 5.0 / dArr2 : 5.0
dArr1 : 2.6 / dArr2 : 2.6
dArr1 : 2104457164 , dArr2 : 1521118594

java.lang 패키지(임포트 x) 의 System 클래스의 arraycopy 메소드를 사용하여 값을 복사하였습니다.

마찬가지로 배열 객체를 복사한 것이므로 서로 다른 객체를 가르키고 있으며, 해쉬코드도 상이합니다.

원하는 만큼 복사해오기엔 제일 좋은 방법이겠네요!

 

dArr1[1] = 15.3;
		
for(int i = 0; i < dArr1.length; i++) {
	System.out.println("dArr1 : " + dArr1[i] + " / dArr2 : " + dArr2[i]);
}

@콘솔출력값
dArr1 : 3.3 / dArr2 : 3.3
dArr1 : 15.3 / dArr2 : 5.0
dArr1 : 2.6 / dArr2 : 2.6

따라서 원본 dArr1[1]의 값을 변경해도 복사본인 dArr2[1]의 값에는 변함이 없습니다.

 

③ clone

public void test4() {
	boolean[] bArr1 = new boolean[] {true, false, true};
	boolean[] bArr2 = bArr1.clone();
		
	for(int i = 0; i < bArr1.length; i++) {
		System.out.println("bArr1 : " + bArr1[i] + " / bArr2 : " + bArr2[i]);
	}
	System.out.println("bArr1 : " + bArr1.hashCode() + " , bArr2 : " + bArr2.hashCode());
}

@콘솔출력값
bArr1 : true / bArr2 : true
bArr1 : false / bArr2 : false
bArr1 : true / bArr2 : true
bArr1 : 1227229563 , bArr2 : 1982791261

clone메소드를 사용하여 bArr1 배열 객체를 복사해왔으며, 마찬가지로 서로 다른 객체를 가리키며 해쉬코드는 상이합니다.

깊은 복사 중 제일 간단한 방법이네요!

 

bArr1[1] = true;
		
for(int i = 0; i < bArr1.length; i++) {
	System.out.println("bArr1 : " + bArr1[i] + " / bArr2 : " + bArr2[i]);
}

@콘솔출력값
bArr1 : true / bArr2 : true
bArr1 : true / bArr2 : false
bArr1 : true / bArr2 : true

따라서 원본 bArr1[1]의 값을 변경해도 복사본인 bArr2[1]의 값에는 변함이 없습니다.