본문으로 바로가기

어떠한 값이 복사되는데 크게 shallow copy(얕은 복사)와 deep copy(깊은 복사) 두 가지가 있습니다

 

<얕은복사(shallow copy)>

간단히 말하자면 얕은복사는 한쪽에서 수정이 발생되면 다른쪽에도 영향을 끼쳐 같아지게 됩니다.

복사한 배열에서 어떠한 값을 수정하면 원래 배열에도 변경된 값이 들어가게 됩니다.

다음 예제를 봅시다

 

- 1차원 배열의 경우

int[] a = new int[1];
a[0] = 1;
int[] b = a;

// 값 변경
b[0] = 2;

// 2,2 출력
System.out.println(a[0] + ", " + b[0]);

1차원 배열의 얕은 복사는 대입 연산을 이용하는 것입니다.

대입 연산을 이용해서 복사하게 되면 위의 경우 b배열의 값을 변경했을때 a 배열의 값도 변경됩니다.

 

- 2차원 배열의 경우

 위의 코드를 실행해서 출력해보면 0,0의 a의 값이 둘다 100으로 바뀌어서 출력이 된것을 볼 수 있습니다.

이는 shallow copy, 즉 얕은 복사가 되었기 때문에 하나의 값이 변경되서 복사된 배열의 값도 변경되게 됩니다.

아마 이 것을 의도하고 배열을 복사한 것은 아니겠죠???

 

 위와 같은 방식으로 해도 얕은 복사가 됩니다. 객체의 배열이기 때문이에요

arr[i].clone()을 이용해서 열마다 복사해서 다른 배열을 만드려했지만 같은 객체를 가지고 복사한 것이기 때문에

깊은 복사가 되지 않습니다.

코드를 한 번 실행해보세요!!

 

<깊은 복사(deep copy)>

깊은 복사는 배열을 복사 한 후에 한쪽 값을 수정해도 다른 배열에 영향을 끼치지 않습니다.

만약 원래 배열의 값을 수정했다해도 복사한 배열의 값은 복사했을때 그대로의 값이 저장되어있습니다.

먼저 1차원 배열의 깊은 복사에 대해서 알아보겠습니다!!

 

<1차원 배열의 깊은 복사>

1차원 배열의 깊은 복사는 배열.clone() 함수를 이용하면 정말 간단하게 할 수 있습니다( 일반 자료형의 경우)

아니면 for문을 이용해 값을 그대로 넣어주어도 됩니다.

 

- 일반 자료형 배열의 경우

**주의

객체 배열의 경우 .clone()을 사용하시면 깊은 복사가 안됩니다!!!

객체는 주소값을 가지고 있기 때문이에요

마찬가지로 2차원 배열의 경우도 각각 row에 대한 주소값을 가지고 있기 때문에 deepCopy가 안됩니다.

 

** arraycopy를 이용한 방법

System.arraycopy를 이용할 수도 있습니다.

이 함수의 파라미터는 다음과 같습니다.

System.arraycopy(src, srcPos, dest, destPos, length)

src: 복사할 배열

srcPos: 복사할 배열의 시작위치

dest: 붙여넣을 배열

destPos: 붙여넣을 배열의 시작위치

length: 복사할 길이

그래서 이 함수를 사용하면 다음과 같읕 코드로 1차원 배열을 복사할 수 있습니다.

 

- 객체 배열의 경우

1차원 객체 배열을 복사하기 위해서는 for문을 돌며 넣어주는데 이때 마다 새로운 객체를 new로 생성하며

직접 값을 넣어주어야 합니다.

그래야 다른 새로운 객체를 담은 배열로 복사된 배열을 가질 수 있습니다ㅏ.

출력해보면 dest의 값만 변경되어 출력되는 것을 볼 수 있습니다.

 

<2차원 배열의 깊은 복사>

1. 그냥 이중 for문을 순회하며 하는 방법!

2. System.arraycopy를 이용하는 방법

 

1. 이중 for문을 이용하기

이 방법은 기본 자료형인 경우에 사용하면 간단하게 사용하실 수 있어요

 

int형, cha형, string형 2차원 배열 같은 경우 이와 같이 값을 직접 넣어주셔도 deepCopy가 잘됩니다.

복사한 배열의 값을 변경한 이후

배열을 복사한 이후 복사한 배열의 값을 변경해도 원래 배열에 영향을 끼치지 않는 깊은 복사가 잘 되었다.

 

이중 for문을 이용한 복사

위의 출력된 결과를 보면 두 가지 방법의 복사 모두 깊은 복사가 잘 되었음을 알 수 있다.

 

2. System.arraycopy를 이용하는 방법

일단 기본 자료형인 경우에 다음 코드와 같이 System.arraycopy 메소드를 이용해 2차원 배열을 복사할 수 있어요

1차원 배열을 2차원 배열의 row 길이 만큼 복사한다고 보시면 됩니다.

 

위 deepCopy 함수를 이용해서 복사를 한 경우에도 deepCopy가 잘 되는 것을 보실 수 있을거에요

 

- 2차원 객체 배열의 복사

2차원 객체 배열의 복사를 할 경우 arraycopy나 clone을 이용해서 복사할 수가 없습니다.

그래서 for문을 돌면서 값을 직접 복사하며 객체를 새로 생성해야 합니다.

 

다음과 같이 복사 생성자를 만들어서 더 깔끔하게 복사할 수도 있습니다. 약간 취향 차이??

class Pos{
	int a;
	int b;
	
	Pos(int a, int b){
		this.a = a;
		this.b = b;
	}
	
	Pos(Pos p){
		this.a = p.a;
		this.b = p.b;
	}
}

public static Pos[][] deepCopy(Pos[][] src){
	if(src == null) return null;
	Pos[][] dest = new Pos[src.length][src[0].length];

	for(int i=0; i<src.length; i++) {
		for(int j=0; j<src[i].length; j++)
			dest[i][j] = new Pos(src[i][j]);
	}
	return dest;
}

 

이렇게 정말 길게 자바에서 배열을 복사하는 모든 방법에 대해서 알아보았습니다.

이제 1차원 배열이든 2차원 배열이든 객체 배열이든 복사는 마스터했네요 ㅎㅎㅎ

알고리즘을 풀다보면 원래 배열을 손상시키지 않고 값을 변경해서 사용해야 할 경우가 있어서

복사해야할 때가 있는데 이제 까먹지는 않겠네요 ㅎㅎ

열공하세요!!


댓글을 달아 주세요