JavaStudy

ITEM 11 : clone 메소드는 신중하게 오버라이드 하자

  • Cloneable 인터페이스는 복제를 허용하는 객체라는것을 알리는 목적으로 사용하는 믹스인 인터페이스 이다. 하지만 자신이 clone 메소드를 가지고 있지 않으며 Object 클래스의 clone 메소드는 사용에 제약이 있다. (아무런 추상 메소드를 가지고 있지 않다)
  • Cloneable 인터페이스가 비록 clone 함수를 가지고 있지는 않지만 구현하지 않으면 protected clone 함수에서 CloneNotSupportedException 예외가 발생한다.(정장적인 인터페이스 사용법과 다르다. 특별히 protected 메소드의 동작 여부를 결정함)
    • Object 를 상속한 클래스에서 implement Clonable 을 해주지 않아도 Object 의 clone 함수가 불러지지 않는다면 CloneNotSupportedException 발생 안할수도 있다.
  • 복제를 할때는 어떤 생성자도 호출되지 않는다.
    • x.clone() != x
    • x.clone().getClass() == x.getClass()
    • x.clone().eqauls(x) == true // 항상 그런거는 아님.
  • 수퍼 클래스의 clone 메소드를 오버라이드 할 경우 서브 클래스의 clone 에서는 반드시 super.clone 을 호출하여 얻은 객체를 반환해야 한다.
  • java 1.5 이상해서는 제네릭의 일부기능으로 convariant return type 기능이 추가됬다. 서브 클래스의 오버라이딩한 메소드에서는 반환 객체의 더많은 정보를 제공할수 있으며 클라이언트 코드에서는 반환 객체를 서브 클래스 타입으로 캐스팅 할 필요없다.

       // object clone() 이 아니여도 된다. return 타입에 되서는 Genric 기능이 제공됨!
       @Override public PhoneNumber clone() {
         try {
           return (PhoneNumber) super.clone();
         } catch(CloneNotSupportedException e) {
           throw new AssertionError(); //여기서는 이 예외가 생길 수 없다
       }
    
  • Stack 과 같은 콜랙션을 clone 할 경우
       @Override public Stack clone() {
         try {
           Stack result = (Stack) super .clone();
           result.elements = elements.clone();
         } catch(CloneNotSupportedException e) {
             throw new AssertionError(); //여기서는 이 예외가 생길 수 없다
         }
    
  • 고급 프로그래머가 아니라면 clone 을 사용하지 않고 new TreeSet(s) 형태처럼 clone 없이 변환 생성자를 사용하는것이 좋다.
  • Cloneable 은 배열 복제 정도아니면 되도록이면 clone 메소드를 전혀 오버라이드 하지 않고 호출도 안하는게 좋다.