파이썬을 공부할 때도 얕은 복사, 깊은 복사에 대한 이야기는 상당히 많이 나옵니다. 톡이나 메일로 받은 질문 중에서 높은 빈도로 있었던 것 중 하나였습니다. 얕은 복사는 주솟값을 복사합니다. 즉, 사본이 바뀐다면 원본도 바뀝니다. 깊은 복사는 내용물을 복사합니다. 그렇기 때문에, 사본을 복사해도 원본이 바뀌지 않습니다.

 

 간단한 예제 프로그램을 보면서 이해해 봅시다.

 

 


 프로그램 1을 봅시다.

 

 

 저는 Monster 객체 2개를 생성했습니다. 하나는 hp가 3700이고 데미지가 270인 몬스터를 생성했습니다. 그리고 다른 하나 b에는 a를 집어 넣었는데요. 이 때 어떤 일이 일어나는지 봅시다.

 

 

 a는 새로 생성된 객체를 가리킬 겁니다. 그런데 b에다가 a의 값을 넣었어요. 그러면 b도 같은 객체를 가리킬 겁니다.

 

 

 그 다음에 b.hp의 값과 b.da의 값을 바꾸었습니다. b가 가리키는 객체는 hp가 3700이고 데미지가 270인, 즉 15번째 줄에서 새로 생성한 객체였습니다. 결국 a가 가리키는 객체의 내용을 바꿉니다. 사본을 바꾸었는데 원본까지 같이 바뀌었어요. 이건, a와 b가 같은 객체를 참조하기 때문입니다.

 

 

 이제 실행 결과를 봅시다.

 

 

 분명 저는 사본을 바꾸었는데 원본까지 바꾸었다는 것을 알 수 있어요.

 

 


 Java에서 2차원 배열은 어떻게 복사하면 좋을까요?

 

 

 프로그램 2를 실행해 봅시다. 그러면, arr을 출력하는데 arr[0][0]의 값이 0이 아닌, 10이 나온다는 것을 알 수 있어요. 이건 왜 그럴까요? 참조가 복사되었기 때문입니다.

 

 

 이것을 brr에 복사해 봅시다.

 

 

같은 공간을 참조하고 있어요. brr[0][0]에다가 10을 넣으면 연두색으로 칠한 부분이 10으로 바뀔 겁니다.

 

 

 그렇기 때문에 arr[0][0]을 출력하게 되면 10이 출력됩니다.

 

 

 쉽게 말해서, malloc으로 2차원 배열을 할당할 때를 생각해 보세요. 보통 2차 포인터 변수가 1차 포인터 변수 n개를 저장하는 공간을 가리키게 하고, 1차 포인터 변수 n개가 각각 원소 t개를 가리키게끔 동적할당을 하잖아요. 그거랑 동일하다고 생각하시면 편해요. 그러면 쉽게 이해하실 수 있을 거에요. 그러면 2차원 배열의 내용물들이 복사가 되게 하려면 어떻게 해야 할까요?

 

 


 간단합니다. 그림을 보면서 이해해 봅시다.

 

 

 brr[i]가, 새로 할당된 배열 객체를 가리키게 합시다. 이는 for문을 돌면서 brr[i] = new int[5]; 등으로 할 수 있어요. 그 다음에는, 초록색으로 칠한 부분이 원본이라고 하면, 파란색으로 칠한 부분은 사본입니다. arraycopy 함수를 이용해서 복사하면 됩니다. 즉, original은 arr[i]가 되고, 사본은 brr[i]가 됩니다.

 

 이것을 코드로 옮겨보겠습니다.

 

 

 13번째 줄에서, int형 5개짜리 배열 객체를 새로 만듭니다. 그리고 그것을 brr[i]가 가리키게 합니다. 그 다음에, arr[i]가 가리키는 객체의 내용을 brr[i]로 복사하고 있어요. 내용이 어떤 건가요? [0, 0, 0, 0, 0] 입니다. 내용을 담고 있어요. 객체가 아니라. 즉, 배열의 내용이 복사됩니다. 참조가 복사되는 것이 아닙니다. 깊은 복사가 되었다고 합니다.