어떠한 값이 복사되는데 크게 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가 잘됩니다.
배열을 복사한 이후 복사한 배열의 값을 변경해도 원래 배열에 영향을 끼치지 않는 깊은 복사가 잘 되었다.
위의 출력된 결과를 보면 두 가지 방법의 복사 모두 깊은 복사가 잘 되었음을 알 수 있다.
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차원 배열이든 객체 배열이든 복사는 마스터했네요 ㅎㅎㅎ
알고리즘을 풀다보면 원래 배열을 손상시키지 않고 값을 변경해서 사용해야 할 경우가 있어서
복사해야할 때가 있는데 이제 까먹지는 않겠네요 ㅎㅎ
열공하세요!!