이펙티브 자바 #item13 clone 재정의는 주의해서 진행하라

임현규·2023년 1월 11일
0

이펙티브 자바

목록 보기
13/47
post-thumbnail

Cloneable

Cloneable은 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이스이다.

Cloneable은 조금 희한하게 설계가 되었는데 그 이유는 interface 메서드에 clone이 없다는 점이다. 이것은 자바를 만들 때 의도한 목적으로 만들지 못한 잘못된 예라고 책에서는 설명한다.

일반적으로 clone이 선언된 곳은 Object이고 접근 제어자가 protected이다. 그래서 cloneable 만을로는 객체의 clone을 호출할 수 없다. 하지만 clone()은 꽤나 사용되기 때문에 활용방법을 알아두는 것이 도움이 된다.

clone() 메서드의 구현을 결정하는 것은 Cloneable을 이용해 구현하면 된다.

이때 지켜야할 일반 규약은 다음과 같다.

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

이 규약은 문서에도 잘 나와있다.

Cloneable을 활용해 clone을 구현하기

@Override
public PhoneNumber clone() {
	try {
    	return (PhoneNumber) super.clone();
    } catch(CloneNotSupportedException e) {
    	throw new AssertionError(); // 일어날수 없는 일이지만 checked exception이라 ㅠㅠ
    }
}

super.clone()을 이용해 복사하고 형변환해주어도 쉽게 성공한다. 아쉬운 점은 CloneNotSupportedException이 checked Exception이기 때문에 일어나지 않을 일이여도 반드시 try catch를 이용해 잡아주어야 한다는 점이다.

그러나 위와 같은 코드는 문제가 있다. 위에 간단한 복사는 내부에 가변상태의 변수가 없음을 가정하고 사용하는 것이다. 만약 가변 상태의 변수가 있다면, 얕은 복사가 일어날 것이고, 이것은 새로운 객체인줄 알았지만 내부 변수는 서로간의 주소를 공유하는 사태가 벌어질 수 있다. 새로운 객체는 그 객체간 정보를 서로 공유하면 안된다. 그런 점에서 내부적으로 값을 순회하며 깊은 복사를 활용할 필요가 있다.

Cloneable 보단 생성자, 팩토리를 활용

사실 Clone() 하는 일은 생성자가 대신할 수 있다. Clone()이 생각보다 활용되고 있긴 하지만 생성자, 팩토리로 훨씬 깔끔하고 안전하게 구현할 수 있다는 점이다.

복사 팩토리의 예

public static Pizza newInstance(Pizza pizza);

복사 생성자의 예

public Piazza(Pizza pizza);
profile
엘 프사이 콩그루

0개의 댓글