티스토리 뷰

Cloneable은 어떤 객체가 복제(clone)를 허용한다는 사실을 알리는 데 쓰려고 고안된 믹스인(mixin) 인터페이스다. 기본적인 문제는 이 인터페이스에는  clone 메서드가 없으며, Object의 clone 메서드는 protected로 선언되어 있다는 것이다.

Cloneable 인터페이스에 아무런 메서드도 없다면 대체 Cloneable이 하는 일은 무엇인가? protected로 선언된 Object의 clone 메서드가 어떻게 동작할지 정한다. 만일 어떤 클래스가 Cloneable을 구현하면, Object의 clone 메서드는 해당 객체를 필드 단위로 복사한 객체를 반환한다. Cloneable을 구현하지 않은 클래스라면 clone 메서드는 CloneNotSupportedException을 던진다. 이상한 구조를 보이고 있지만, Cloneable의 경우에는 상위 클래스의 protected 멤버가 어떻게 동작할지 규정하는 용도로 쓰이고 있다.

clone의 일반적인 규약은 다음과 같다.

  • x.clone() != x

위의 조건은 항상 참이어야 한다. 객체를 복사했을 뿐이지 동일한 객체는 아니기 때문이다.

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

위 조건은 참이 될 수도 있지만, 반드시 그래야 하는 것은 아니다.

  • x.clone().equals(x)

위 조건도 참이 될 수도 있지만, 반드시 그래야 하는 것은 아니다. 객체를 복사하면 보통 같은 클래스의 새로운 객체가 만들어지는데, 내부 자료구조까지 복사해야 될 수도 있다. 그리고 어떤 생성자도 호출되지 않는다. 이런 점 때문에 생성자처럼 구현해야 할 필요가 있다. 참조값이 아닌 참조된 대상 자체를 다시 복사해야 한다는 의미이다. 이때 참조값을 갖고 있는 변수는 final로 선언되지 않아야 한다.

public class Stack {
	Object[] elements;
    ...
    
    @Overrie
    public Stack clone() {
    	try {
        	Stack result = (Stack)super.clone();
        	result.elements = elements.clone();
        	return result;
        } catch (CloneNotSupportedException e) {
        	throw new AssertionError();
        }
    }
}

사실상, colne 메서드는 또 다른 형태의 생성자다. 원래 객체를 손상시키는 일이 없도록 해야 하고, 복사본의 불변식(invariant)도 제대로 만족시켜야 한다. Stack의 clone 메서드가 제대로 동작하도록 하여면 내부구조도 복사해야 한다.

이처럼 clone()을 재정의해서 사용할 경우, 수 많은 고려할 점들이 있다. 이처럼 clone()은 객체의 모든 데이터에 대한 deep copy 기능을 제공하거나, 아예 복제 기능을 제공하지 않는 것이 낫다. 예를 들어, 변경 불가능한 클래스는 객체 복제를 허용하지 않는 것이 맞다. 복사본은 원래 객체와 논리적으로 구별이 불가능할 것이기 때문이다.

객체 복제를 지원하는 다른 좋은 방법은, 복사 생성자(copy constructor)나 복사 팩토리(copy factory)를 제공하는 것이다.

pulbic Yum(Yum yum); // copy constructor
public static Yum newInstance(Yum yum) // copy factory
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함