본문 바로가기

개발공부/스파르타코딩

[ 정규 ] Java 문법 종합반 2주차

궁금한 내용

강의에서 Deep Copy를 할 때 clone과 copyOf을 설명해 줬으며, copyOf를 사용하라고 알려줬다. clone은 2차원 배열 이상을 들어가면 복사가 제대로 이루어지지 않는다는 문제가 있기 때문이라고 했다. 정말 copyOf가 clone보다 깊은 복사를 더 잘 수행해 내는 것인지 의문이 들었다. copyOf도 똑같은 이슈가 존재한다면 어떤 방법을 사용하면 좋을지에도 고민이 되는 것 같다.

메서드 분석

정확한 동작을 파악하기 위해 clone과 copyOf의 코드 내부를 확인해보기로 했다. 하지만 두 메서드를 타고 들어갔을 때 사용되는 clone , arraycopy가 native 코드로 작성이 되어 있어 들여다보지 못했다. 이후에 native 코드까지 확인할 수 있다면 봐 보는 것도 좋겠다.

 

[ Object.clone 내부 코드 ]

@IntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;

 

[ Arrays.copyOf 내부 코드 ]

@IntrinsicCandidate
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

@IntrinsicCandidate
public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

코드 동작 확인

현재 내가 native 코드를 확인할 방도가 없어서 간단하게 코드의 동작을 확인해 비교해 보기로 했다. clone과 copyOf 모두 배열을 새로 만들어 복사한 배열에 할당을 하는 것을 볼 수 있다. 하지만 두 메서드 모두 새로운 배열 요소들의 주소값에는 기존 값들을 그대로 할당을 하는 것을 볼 수 있다.

 

[ Object.clone 적용 ]

int[][] array = {{1,2,3,4}, {2,3,4,5}};
int[][] copyArray = array.clone()

System.out.println(array == copyArray)    // False
System.out.println(array[0] == copyArray[0]) // True

 

[ Arrays.copyOf 적용 ]

int[][] array = {{1,2,3,4}, {2,3,4,5}};
int[][] copyArray = Arrays.copyOf(array, array.length)

System.out.println(array == copyArray)    // False
System.out.println(array[0] == copyArray[0]) // True

문제가 될 수 있는 것

clone, copyOf 무엇을 사용하든 내부 원소들까지 전부 새롭게 만들어져 복사가 되지 않는다. 내부 원소들이 같은 곳을 참조하기 때문에 변경을 했을 때 다른 배열에도 영향을 준다는 것이다. 이건 다른 클래스의 객체들에 적용을 해도 마찬가지일 것이다.

결론

clone, copyOf가 제공하는 정도의 복사를 바란다면 써도 되는 것 같다. 정확하게 인지하고 있다면 말이다. 더 깊은 복사가 필요하다면 Object의 clone을 재정하는 방식을 사용해 볼 수 있을 것 같다. 추가적으로 생성자와 복사 팩터리를 사용해 보는 방법도 있다.

 

[ clone 재정의 ]
@Override public Object clone() {
    // logic
}

[ 생성자를 통한 복사 ]
public DeepCopy(DeepCopy deepcopy){
    // logic
}

[ 복사 팩터리 ]
public static Deepcopy newInstatnce(Deepcopy deepcopy){
    // logic
}