Java

[Effective Java] 아이템 13. clone 재정의는 주의해서 진행하라.

quedevel 2022. 5. 24. 13:55
728x90
반응형

Cloneable은 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이스지만, 아쉽게도 의도한 목적을 제대로 이루지 못했다.

가장 큰 문제는 clone 메서드가 선언된 곳이 Cloneable이 아닌 Object이고, 그마저도 protected라는 데 있다.

protected native Object clone() throws CloneNotSupportedException;
  • Object 명세에 적힌 규약 ❗

    이 객체의 복사본을 생성해 반환한다. '복사'의 정확한 뜻은 그 객체를 구현한 클래스에 따라 다를 수 있다.

    일반적인 의도는 다음과 같다. 어떤 객체 x에 대해 다음 식은 참이다.


    x.clone() != x


    또한 다음 식도 참이다.


    x.clone().getClass() == x.getClass()


    하지만 이상의 요구를 반드시 만족해야 하는 것은 아니다.

    한편 다음 식도 일반적으로 참이지만, 역시 필수는 아니다.


    x.clone().equals(x)


    관례상, 이 메서드가 반환하는 객체는 super.clone을 호출해 얻어야 한다.

    이 클래스(Object를 제외한) 모든 상위 클래스가 이 관례를 따른다면 다음 식은 참이다.


    x.clone().getClass() == x.getClass()


    관례상, 반환된 객체와 원본 객체는 독립적이어야 한다.

    이를 만족하려면 super.clone으로 얻은 객체의 필드 중 하나 이상을 반환 전에 수정해야 할 수도 있다.


  • 가변 상태를 참조하지 않는 클래스용 clone 메서드
    @Override
    public Item13 clone() {
      try {
          return (Item13) super.clone();
      } catch (CloneNotSupportedException e) {
          throw new RuntimeException();
      }
    }

    이 메서드가 동작하게 하려면 Item13의 클래스 선언에 `Cloneable`을 구현해야한다.
    만약 구현하지 않는다면 `CloneNotSupportedException`을 던지게 된다.
    `clone` 메서드는 사실상 생성자와 같은 효과를 낸다.
    즉, `clone`은 원본 객체에 아무런 해를 끼치지 않는 동시에 복제된 객체의 불변식을 보장해야한다.
    따라서, 기본 원칙은 '복제 기능은 생성자와 팩터리를 이용하는게 최고'라는 것이다.
    단, 배열만은 `clone` 메서드 방식이 가장 깔끔한, 이 규칙의 합당한 예외라 할 수 있다.
    (배열은 각 elements도 재귀적으로 `clone`을 해야하기 때문이다.)

참고 자료

Joshua Bloch, 『Effective Java 3/E』, 개앞맵시 옮김, 프로그래밍인사이트(2018)
http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788966262281&orderClick=LEa&Kc=

728x90
반응형