HihoBookStudy / EffectiveJava

이펙티브 자바 북스터디입니다.
1 stars 0 forks source link

[Item 13] 배열의 clone()에 대해 #22

Closed ForteEscape closed 2 months ago

ForteEscape commented 3 months ago

Q. 책(p.86)에서 다음과 같이 서술된 부분이 있습니다.

단, 배열만은 clone 메서드 방식이 가장 깔끔한, 이 규칙(객체를 복사할 때 복사 생성자 또는 복사 펙터리 메서드를 활용하라)의 합당한 예외라고 할 수 있다.

Limgayoung commented 3 months ago

일단 배열이 깔끔한 경우는 기본형과 String에 한정되어 있는 듯 합니다. 이것에 대한 이유는 확실하지는 않지만 다음과 같은 것 같습니다.

java에서 int, long, float과 같은 기본형과 String은 값을 바꾸고 싶다면 무조건 = 연산자를 사용해야 합니다. 이를 사용하면 값이 바뀐 배열은 항상 기존과 다른 주솟값을 참조하게 됩니다. 해당 배열은 clone을 사용해 복사본을 만들어 내부의 값을 수정한 순간부터 해당 원소는 다른 주솟값을 참조하게 되고, 이 때문에 기존의 배열에는 아무 영향을 주지 않습니다.

하지만 기본형과 String이 아닌, 예를 들어 직접 만든 class 배열일 경우에는 다릅니다. clone을 사용해 복사본을 만들면 배열의 각 칸은 같은 주소를 참조하고 있습니다. 값을 바꾸는 경우에 = 연산자를 사용해 새로운 객체를 생성해 넣어준다면 새로운 주소를 참조해서 이전의 배열에 영향을 주지 않습니다. 하지만 = 연산자를 사용하지 않고 .으로 접근해 값을 바로 변경한다면 (setter도 마찬가지) 기존의 주소값(원래와 동일함)의 값을 변경하기 때문에 clone을 사용한 배열의 값을 변경했음에도 기존 배열에 영향을 주게 됩니다.

배열을 clone할 때 객체의 clone은 사용하지 않기 때문에 객체의 clone을 재정의하더라도 위와 같은 상황을 해결하지 못합니다.

혹시 위의 가정이 틀렸거나 다른 이유가 있다면 말해주시면 감사하겠습니다.

Limgayoung commented 3 months ago

그리고 테스트 결과 clone()과 복사 생성자를 활용한 경우의 성능 차이는 거의 없지만 복사 생성자가 더 빠릅니다. 하지만 이 차이가 거의 나지 않아서 코드를 복잡하게 만드는 것보다 clone을 이용해 깔끔하게 짜는 것이 더 낫다고 판단한 것 같습니다.

public class ArrayClonePerformance {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8,9,10};

        //peformance
        //clone 사용해서 복사
          long before = System.currentTimeMillis();

          for(int i=0;i<1000000000;i++)
          {
              arr.clone();
          }
          System.out.println("Time Required for Clone: "+ (System.currentTimeMillis()-before));

        //peformance
          //clone을 사용하지 않고 생성자 복사
          //생성자 복사를 진행할 때에는 새로운 배열 만들어서 하나씩 값 대입하게 됨
          before = System.currentTimeMillis();
          for(int i=0;i<1000000000;i++)
          {           
              ArrayCopy(arr);         
          }
          System.out.println("Time Required for Copy of: "+ (System.currentTimeMillis()-before));
    }

    public static int[] ArrayCopy(int[] arr) {
        int[] copy = new int[arr.length];
          for(int j=0;j<arr.length;j++) {
              copy[j] = arr[j];
          } 
          return copy;
    }
}

결과

Time Required for Clone: 8124
Time Required for Copy of: 7988