System의 arrayCopy는 생각보다 레퍼런스 내에서 상당히 많이 보이는 메서드입니다. 배열을 복사하는 것은 상당히 많이 쓰이기 때문입니다. 이것이 어떤 함수인지 간단하게만 언급하도록 하겠습니다. 분석까지는 하지 않겠습니다.

 

 

 먼저, src는 source를 의미합니다. 원본이 들어있는 배열과, 복사를 시작할 위치를 받습니다. 그리고, 복사된 값을 넣을 배열과, 넣기 시작할 위치를 받습니다. 그리고 얼마나 넣을 것인지를 받습니다. 여기까지만 보면 도무지 무슨 이야기인지 잘 모르겠어요.

 

 


 예제를 보도록 하겠습니다.

 

 예를 들어서, 1번째 인자가 arr, 2번째 인자가 0, 3번째 인자가 brr, 4번째 인자가 10, 5번째 인자가 10이라고 해 보겠습니다. 이 경우에는, 배열 arr의 0번째 원소부터 x개를, brr의 10번째 위치부터 copy를 하겠다는 의미인데요. 그 갯수가 10개라는 의미입니다. 이를 다시 그림으로 그려보겠습니다.

 

 

 배열 2개가 있습니다. arr과 brr이 있습니다. for 루프 2번을 돌면 arr과 brr은 위와 같이 초기화가 되어 있습니다.

 

 

 먼저, 원본 배열에서 0번째 위치를 뽑습니다.

 

 

 그리고 복사가 된 값이 들어갈 배열에서 10번째 위치를 뽑습니다. 그런데 이 정보만 보고, original에서 destination으로 copy를 할 수는 없습니다. 왜냐하면 1개만 복사할지, 100만개를 복사할지, 10억개를 복사할지, 그에 대한 정보를 넘겨주지 않았기 때문입니다. 이에 대한 정보를 받아야 할 듯 싶은데. docs에 나와 있는 5번째 인자의 이름은, length라고 되어 있습니다.

 

 

 즉, 몇 개의 원소를 연속적으로 복사할 것인지에 대한 정보를 5번째 인자로 받습니다.

 

 

 예제의 실행 결과는 위와 같습니다.

 


 이제, java의 arrayCopy에 대한 대표적인 이슈에 대해서 고민해 보도록 하겠습니다.

 

 

 Obj 클래스를 선언하였습니다. 이것은, 그냥 int형 변수 하나를 boxing 하는 mutable한 객체라고 생각합시다.

 

 

 위 코드의 결과는 어떻게 나올까요? 사실, 0, ... , 19 순서대로 출력이 될 거 같지만, 아닙니다.

 

 

 왜 그럴까요? 28번째 줄의 arrayCopy가 수행되기 직전의 메모리는 다음과 같습니다.

 

 

 서로 별개의 객체를 가리키고 있었습니다. 그런데, copy가 수행된 순간에 아래와 같이 바뀝니다.

 

 

 arr[0]과 brr[0]이 가리키는 대상 객체가 같아져 버립니다. 이는 복사되는 값이, 실 값이 아니라, 객체를 가리키는 무언가이기 때문입니다. 흔히, 얕은 복사라고 알려진 것입니다. 따라서, arr[0]이 가리키고 있는 객체의 field x를 30으로 setting 하면 아래와 같이 바뀌게 됩니다.

 

 

 arr[0]과 brr[0]의 field x값은 30으로 같게 되어 버리는 것입니다. 분명히 brr[0].set(30)을 하는 코드는 없었음에도 불구하고요. 이를 어떻게 해결해야 할 지는 다음에 언급을 해 보도록 하겠습니다.

 

 

 그러면, overlap 이슈가 생기면 어떨까요? 25번째 줄을 보면, 그러하다는 것을 알 수 있습니다.

 

 

 이에 대한 언급 또한 doc에 되어 있습니다. 그러한 경우에, 임시 배열에 복사가 되고, 그 배열로부터, 다시 복사가 될 위치에 copy 된다고 되어 있어요. 그런데, copy safe한지 모른다면 어떻게 해야 할까요? 임시 배열을 하나 선언을 합니다. 이를 temp라고 하겠습니다.

 

 

 30번째 줄에서, arr에서 temp로 복사를 하고, 31번째 줄에서 temp에서 brr로 복사를 한다는 것을 알 수 있어요. 임시 공간을 만들어 놓고 2번에 나눠서 copy를 하면 overlap이 되는 경우에도 안전하게 목적을 달성할 수 있습니다.