Override clone judiciously
- 2판 제목 : clone을 재정의할 때는 신중하라
- 3판 제목 : clone 재정의는 주의해서 진행하라
Cloneable
인터페이스는 어떤 객체가 clone
함수를 통해 복제가능하다는 것을 알리기 위한 인터페이스이다.
1 | public interface Cloneable { |
실제로 구현을 강제하는 메서드도 하나도 없으며, 단지 Object
클래스의 protected
메서드인 clone
함수의 동작 방식을 결정한다.
Cloneable
을 구현한 클래스의 객체에서 clone
을 호출하면 해당 객체의 필드값들을 하나하나 복사한 객체를 반환하고
구현하지않은 객체에서 호출하면 CloneNotSupportException
예외를 발생시킨다.
일반적인 인터페이스와 달리 Cloneable
의 경우 상위 클래스에 정의된 동작 방식을 변경한 것이므로 이러한 구조를 따라하는 것은 권장되지않는다.
참고 불변 객체는 굳이
clone
을 제공하지 않는 것이 좋다.
1. clone 함수의 규약
clone
의 규약은 상대적으로 느슨하다.
객체의 복사본을 반환하는 함수이니만큼 클래스마다 상이할 “복사”의 의미만 잘 정의해서 충족하면 된다.
x.clone() != x
위의 조건은 반드사 참이어야 한다.
x.clone().getClass() == x.getClass()
위의 조건은 참이긴 하겠지만 반드시 참이어야하는 것은 아니다.
x.clone().equals(x)
위의 조건은 참이긴 하겠지만 반드시 참이어야하는 것은 아니다.
객체를 복사하는 경우 보통 같은 클래스의 새로운 객체가 만들어지며, 어떠한 생성자도 호출되지 않는다.
2. 예제
다시 PhoneNumber
클래스를 가져와보자.
1 | public final class PhoneNumber implements Cloneable { |
try-catch
블록이 필요한 이유는 상술한 CloneNotSupportedException
예외를 던지고 있기 때문이다. 물론 Cloneable
을 구현하였으므로 발생하진 않을 것이다.
1 | public class Object { |
이번엔 Stack
예제를 보자.
1 | public class Stack { |
Stack
클래스는 가변적인 객체를 참조하고 있으므로 아래와 같이 clone
을 재정의한다.
1 |
|
원본 객체를 유지하면서 복제한 객체의 불변을 유지하기 위해 elements
배열의 clone
을 호출한 것을 확인할 수 있다.