개발하는 두더지

[Effective Java 규칙11] clone을 재정의할 때는 신중하라 본문

Java,Android

[Effective Java 규칙11] clone을 재정의할 때는 신중하라

덜지 2018. 9. 14. 16:08

[Effective Java 규칙11] clone을 재정의할 때는 신중하라

Effective Java 2/E 책과 구글링을 통해 내용을 정리하고 개인적인 견해가 포함된 글입니다.



어떤 클래스가 Cloneable 인터페이스를 구현하면 Object의 protected 인 clone 메서드가 어떻게 동작할지를 정하게된다.

먼저 clone 메서드의 규약은 느슨한 편인데 아래 규약을 살펴보자


객체의 필드단위까지 복사하여 반환하는데 다음의 조건이 일반적으로 충족되야 한다

x.clone() != x    이 조건은 참이어야 한다

x.clone().getClass() == x.getClass()   이 조건은 참이겠지만 반드시 그래야하는 것은 아니다

x.clone().equals(x)   이 조건도 참이겠지만 반드시 그래야하는 것은 아니다

객체를 복사하면 보통 같은 클래스의 새로운 객체가 만들어지는데, 어떤 생성자도 호출되지 않는다.


음. 무슨 내용을 알려주고싶은건지 확실히 이해가 안간다.



final이 아닌 클래스에 clone을 재정의할 때는 클래스에 Cloneable 인터페이스를 구현하고(메소드가 하나도 없기때문에 구현할 건 없다. 클래스에 Cloneable 인터페이스를 사용하겠다고 선언하는 것 뿐) clone 메소드를 오버라이드하고 반드시 super.clone을 호출해 얻은 객체를 반환해야 한다. 이렇게 안한다면  CloneNotSupportedException에 걸리게 된다.


@Override
protected PhoneNumber clone(){
try {
return (PhoneNumber) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}


clone할 경우에 주의해야할 점이있는데 복제할 객체가 변경가능한 객체의 참조 필드를 가지고 있다면 문제가 생긴다. 기본자료형 필드의 경우 그대로 복사가되지만 배열의 경우 원래 객체의 배열을 참조하게 되는 문제가 발생한다. 배열의 경우 super.clone()을 통해서 얻은 객체에 배열의 clone을 다시 set 해줘야 한다.

clone은 또다른 형태의 생성자이므로 원래 객체를 손상시키는 일이 없어야 하며 복사본의 불변식을 만족시켜야 한다.

배열객체.clone을 하면 자바 1.5부터 반환되는 배열의 컴파일 시점 자료형으로 복사가되므로 따로 형변환 할 필요가 없다.

@Override public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch( CloneNotSupportedException e) {
throw new AssertionError();
}
}

( 규칙 6에서 사용한 Stack 클래스의 clone 재정의 )


생각보다 cloneable 인터페이스를 구현하고 clone 메서드를 재정의하는 작업은 복사하기위해 많은 코드들이 필요하며 신경써야할 부분들이 많다.

그래서 객체 복제를 지원하는 좋은 방법은 복사 생성자나 복사 팩터리를 제공하는 것이다.

Cloneable/clone보다 장점들이 많다. 객체 생성 수단에 의존하지 않고, 어려운 규약을 지킬 필요도 없고, final 과 충돌이 일어나지 않으며, 불필요한 예외 검사를 할 필요가 없고, 형 변환도 필요없다. 이러한 인터페이스 기반의 생성자와 팩터리는 변환 생성자 (conversion constructor)로 더 잘 알려져 있으며 예를들면

HashSet객체 s가 있고, 이것을 TreeSet으로 복제하고 싶을 때 변환 생성자를 사용하면 new TreeSet(s)로 만들면 된다.


결론적으로,

Cloneable을 구현하는 인터페이스를 만들지 말아야 하며, 상속을 목적으로 설계하는 클래스는 Cloneable을 구현하지말고 

변환 생성자를 이용하여 복사하는 것이 더 좋은 방법이다.





















Comments