자바(java) 배열의 깊은 복사(deep copy)와 얕은 복사 완벽정리(1차원 배열, 2차원 배열, 객체 배열 복사)
- -
어떠한 값이 복사되는데 크게 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차원 배열의 경우
class Pos{ | |
int a; | |
int b; | |
Pos(int a, int b){ | |
this.a = a; | |
this.b = b; | |
} | |
} | |
public static void main(String args[]) throws IOException{ | |
Pos[][] src = new Pos[10][10]; | |
// initialize array | |
for(int i=0; i<src.length; i++){ | |
for(int j=0; j<src[0].length; j++){ | |
src[i][j] = new Pos(i,j); | |
} | |
} | |
// shallow copy | |
Pos[][] posCopy = shallowCopy3(src); | |
// alter src array | |
src[0][0].a = 100; | |
// print original arr | |
print(src); | |
// print copy arr | |
print(posCopy); | |
} | |
public static Pos[][] shallowCopy(Pos[][] src){ | |
if(src == null) return null; | |
Pos[][] dest = new Pos[src.length][src[0].length]; | |
for(int i=0; i<src.length; i++){ | |
System.arraycopy(src[i], 0, dest[i], 0, src[i].length); | |
} | |
} | |
public static void print(Pos[][] arr){ | |
for(int i=0; i<src.length; i++){ | |
for(int j=0; j<src[0].length; j++){ | |
Pos pos = arr[i][j]; | |
System.out.print("(" + pos.a + ", " + pos.b + ") "); | |
} | |
System.out.println(""); | |
} | |
System.out.println(""); | |
} |
위의 코드를 실행해서 출력해보면 0,0의 a의 값이 둘다 100으로 바뀌어서 출력이 된것을 볼 수 있습니다.
이는 shallow copy, 즉 얕은 복사가 되었기 때문에 하나의 값이 변경되서 복사된 배열의 값도 변경되게 됩니다.
아마 이 것을 의도하고 배열을 복사한 것은 아니겠죠???
class Pos{ | |
int a; | |
int b; | |
Pos(int a, int b){ | |
this.a = a; | |
this.b = b; | |
} | |
} | |
class Main{ | |
public static void main(String args[]) throws IOException{ | |
Pos[][] posCopy2 = new Pos[src2.length][src[0].length]; | |
for(int i=0; i<src2.length; i++) { | |
posCopy2[i] = src2[i].clone(); | |
} | |
posCopy2[0][0].a = 100; | |
print2(src2); | |
System.out.println("복사된 배열"); | |
print2(posCopy2); | |
} | |
public static void print2(Pos[][] arr) { | |
for(int i=0; i<arr.length; i++) { | |
for(int j=0; j<arr[0].length; j++) { | |
Pos pos = arr[i][j]; | |
System.out.print("(" + pos.a + ", " + pos.b + ") "); | |
} | |
System.out.println(""); | |
} | |
System.out.println(""); | |
} | |
} | |
위와 같은 방식으로 해도 얕은 복사가 됩니다. 객체의 배열이기 때문이에요
arr[i].clone()을 이용해서 열마다 복사해서 다른 배열을 만드려했지만 같은 객체를 가지고 복사한 것이기 때문에
깊은 복사가 되지 않습니다.
코드를 한 번 실행해보세요!!
<깊은 복사(deep copy)>
깊은 복사는 배열을 복사 한 후에 한쪽 값을 수정해도 다른 배열에 영향을 끼치지 않습니다.
만약 원래 배열의 값을 수정했다해도 복사한 배열의 값은 복사했을때 그대로의 값이 저장되어있습니다.
먼저 1차원 배열의 깊은 복사에 대해서 알아보겠습니다!!
<1차원 배열의 깊은 복사>
1차원 배열의 깊은 복사는 배열.clone() 함수를 이용하면 정말 간단하게 할 수 있습니다( 일반 자료형의 경우)
아니면 for문을 이용해 값을 그대로 넣어주어도 됩니다.
- 일반 자료형 배열의 경우
class Main{ | |
public static void main(String args[]) { | |
int[] src = new int[10]; | |
// initialize array | |
for(int i=0; i<src.length; i++) { | |
src[i] = i; | |
} | |
int[] dest = deepCopy(src); | |
dest[0] = 100; | |
System.out.println("original 배열"); | |
print(src); | |
System.out.println("복사된 배열"); | |
print(dest); | |
} | |
public static void print(int[] arr) { | |
for(int i=0; i<arr.length; i++) | |
System.out.print(arr[i] + " "); | |
} | |
public static int[] deepCopy(int[] src){ | |
if(src == null) return null; | |
int[] dest = new int[src.length]; | |
dest = src.clone(); | |
return dest; | |
} | |
} |
**주의

객체 배열의 경우 .clone()을 사용하시면 깊은 복사가 안됩니다!!!
객체는 주소값을 가지고 있기 때문이에요
마찬가지로 2차원 배열의 경우도 각각 row에 대한 주소값을 가지고 있기 때문에 deepCopy가 안됩니다.
** arraycopy를 이용한 방법
System.arraycopy를 이용할 수도 있습니다.
이 함수의 파라미터는 다음과 같습니다.
System.arraycopy(src, srcPos, dest, destPos, length)
src: 복사할 배열
srcPos: 복사할 배열의 시작위치
dest: 붙여넣을 배열
destPos: 붙여넣을 배열의 시작위치
length: 복사할 길이
그래서 이 함수를 사용하면 다음과 같읕 코드로 1차원 배열을 복사할 수 있습니다.
class Main{ | |
public static void main(String args[]) { | |
int[] src = new int[10]; | |
// initialize array | |
for(int i=0; i<src.length; i++) { | |
src[i] = i; | |
} | |
int[] dest = deepCopy(src); | |
dest[0] = 100; | |
System.out.println("original 배열"); | |
print(src); | |
System.out.println("복사된 배열"); | |
print(dest); | |
} | |
public static void print(int[] arr) { | |
for(int i=0; i<arr.length; i++) | |
System.out.print(arr[i] + " "); | |
} | |
public static int[] deepCopy(int[] src){ | |
if(src == null) return null; | |
int[] dest = new int[src.length]; | |
for(int i=0; i<arr.length; i++){ | |
System.arraycopy(src, 0, dest, 0, src.length); | |
} | |
return dest; | |
} | |
} |
- 객체 배열의 경우
class Main{ | |
public static void main(String args[]) { | |
Pos[] src = new Pos[10]; | |
// initialize array | |
for(int i=0; i<src.length; i++) { | |
src[i] = new Pos(i,i); | |
} | |
Pos[] dest = deepCopy(src); | |
dest[0].a = 100; | |
dest[0].b = 100; | |
System.out.println("original 배열"); | |
print(src); | |
System.out.println("복사된 배열"); | |
print(dest); | |
} | |
public static void print(Pos[] arr) { | |
for(int i=0; i<arr.length; i++) | |
System.out.print("(" + arr[i].a + ", " + arr[i].b + ") "); | |
} | |
public static Pos[] deepCopy(Pos[] src){ | |
if(src == null) return null; | |
Pos[] dest = new Pos[src.length]; | |
for(int i=0; i<src.length; i++){ | |
src[i] = new Pos(src[i].a, src[i].b); | |
} | |
return dest; | |
} | |
} |
1차원 객체 배열을 복사하기 위해서는 for문을 돌며 넣어주는데 이때 마다 새로운 객체를 new로 생성하며
직접 값을 넣어주어야 합니다.
그래야 다른 새로운 객체를 담은 배열로 복사된 배열을 가질 수 있습니다ㅏ.
출력해보면 dest의 값만 변경되어 출력되는 것을 볼 수 있습니다.
<2차원 배열의 깊은 복사>
1. 그냥 이중 for문을 순회하며 하는 방법!
2. System.arraycopy를 이용하는 방법
1. 이중 for문을 이용하기
이 방법은 기본 자료형인 경우에 사용하면 간단하게 사용하실 수 있어요
public static int[][] deepCopy2(int[][] src){ | |
if(src == null) return null; | |
int[][] dest = new int[src.length][src[0].length]; | |
for(int i=0; i<src.length; i++) | |
for(int j=0; j<src[0].length; j++) | |
dest[i][j] = src[i][j]; | |
return dest; | |
} |
int형, cha형, string형 2차원 배열 같은 경우 이와 같이 값을 직접 넣어주셔도 deepCopy가 잘됩니다.

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

위의 출력된 결과를 보면 두 가지 방법의 복사 모두 깊은 복사가 잘 되었음을 알 수 있다.
2. System.arraycopy를 이용하는 방법
일단 기본 자료형인 경우에 다음 코드와 같이 System.arraycopy 메소드를 이용해 2차원 배열을 복사할 수 있어요
1차원 배열을 2차원 배열의 row 길이 만큼 복사한다고 보시면 됩니다.
public static int[][] deepCopy(int[][] src){ | |
if(src == null) return null; | |
int[][] dest = new int[src.length][src[0].length]; | |
for(int i=0; i<src.length; i++){ | |
System.arraycopy(src[i], 0, dest[i], 0, src[0].length); | |
} | |
return dest; | |
} |

위 deepCopy 함수를 이용해서 복사를 한 경우에도 deepCopy가 잘 되는 것을 보실 수 있을거에요
- 2차원 객체 배열의 복사
2차원 객체 배열의 복사를 할 경우 arraycopy나 clone을 이용해서 복사할 수가 없습니다.
그래서 for문을 돌면서 값을 직접 복사하며 객체를 새로 생성해야 합니다.
class Pos{ | |
int a; | |
int b; | |
Pos(int a, int b){ | |
this.a = a; | |
this.b = b; | |
} | |
} | |
class Main{ | |
public static void main(String args[]) throws IOException{ | |
Pos[][] src = new Pos[10][10]; | |
// initialize array | |
for(int i=0; i<src.length; i++) { | |
for(int j=0; j<src[0].length; j++) | |
src[i][j] = new Pos(i,j); | |
} | |
Pos[][] dest = deepCopy(src); | |
dest[0][0].a = 100; | |
dest[0][0].b = 100; | |
System.out.println("original 배열"); | |
print2(src); | |
System.out.println("복사된 배열"); | |
print2(dest); | |
} | |
public static void print2(Pos[][] arr) { | |
for(int i=0; i<arr.length; i++) { | |
for(int j=0; j<arr[0].length; j++) { | |
Pos pos = arr[i][j]; | |
System.out.print("(" + pos.a + ", " + pos.b + ") "); | |
} | |
System.out.println(""); | |
} | |
System.out.println(""); | |
} | |
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].a, src[i][j].b); | |
} | |
return dest; | |
} | |
} |
다음과 같이 복사 생성자를 만들어서 더 깔끔하게 복사할 수도 있습니다. 약간 취향 차이??
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차원 배열이든 객체 배열이든 복사는 마스터했네요 ㅎㅎㅎ
알고리즘을 풀다보면 원래 배열을 손상시키지 않고 값을 변경해서 사용해야 할 경우가 있어서
복사해야할 때가 있는데 이제 까먹지는 않겠네요 ㅎㅎ
열공하세요!!
소중한 공감 감사합니다