Item 13. clone 오버라이딩은 주의해서 진행하라
clone
protected Object clone() throws CloneNotSupportedException {}
해당 인스턴스의 복사본을 만들어 반환하는 메서드
물리적 주소는 다르나, 동일한 클래스의 인스턴스이며 equals로 비교했을 때 같은 객체를 생성
clone 메서드는 protected이기 때문에 사실상 이 메서드는 외부에서 접근이 불가능
때문에, Java에서는
Cloneable
이라는 인터페이스를 제공해 이를 구현하는 클래스는 clone 메서드를 제공Cloneable
이 clone 메서드를 오버라이딩하도록 강제하는 인터페이스는 아님에 주의
Cloneable
의 올바른 사용 예
Cloneable
의 올바른 사용 예class Item13 implements Cloneable {
@Override
public Item13 clone() {
try {
return (Item13) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
clone 메서드를 public으로 재정의하고, 해당 클래스를 반환하도록 함
반드시 super.clone()을 호출해야 함
모든 하위 클래스에서 이 규약을 지킨다면, 참조형을 제외한 필드들은 모두 잘 복사됨이 보장됨
하지만 참조형 필드는 얕은 복사가 일어날 수 있음
복잡한 가변 데이터 묶음을 갖는 클래스의 경우 clone 메서드의 오버라이딩이 단순히 super.clone()으로 끝나지 않으며, 이후에 이 가변 필드들을 재귀적으로 복사하는 일을 수행해야 함
불변 데이터는 초기화 후 변경이 불가하므로 아예 복사가 어려움
불변 참조형 필드(final reference field)가 포함된 클래스를 완전히 복사하려면 final 한정자를 제거해야 함
위와 같은 사유로
Cloneable
을 구현하여 clone 메서드를 오버라이딩하는 방식은 권장되지 않으며, 복사 생성자 또는 복사 팩터리(정적 메서드) 방식으로 대체할 것을 권고
복사 생성자, 복사 팩터리
복사 생성자
class Item13 {
public Item13(Item13 item13) {
// 여기서 필드들을 직접 세팅
}
}
복사 생성자는 자신과 같은 클래스의 인스턴스를 매개변수로 받아 필드들을 직접 세팅(복사)함
복사 팩터리
class Item13 {
public static Item13 newInstance(Item13 item13) {
// 여기서 필드들을 직접 세팅
}
}
복사 생성자에
Item 1
(생성자 대신 정적 팩토리 메서드) 패턴을 적용한 경우에 해당
복사 생성자, 복사 팩터리의 장점
초기화 단계에 해당하므로 불변 필드들을 복사하는 것이 가능
Cloneable
과 clone 메서드는 문서화된 규약에 의존하기 때문에 클라이언트가 이 규약을 지키지 않을 수 있다는 위험이 있는데, 위의 두 방식은 그러한 위험이 없음Cloneable
을 구현해도 clone 메서드를 오버라이딩하도록 강제하지 않음super.clone()을 반드시 호출해야 함에도, 이를 강제하지 않음
반드시 같은 클래스의 인스턴스를 받지 않아도 됨. 해당 클래스가 구현한 인터페이스를 매개변수로 전달받아도 됨
Last updated