[아이템 13] clone 재정의는 주의해서 진행하라
clone 메서드를 사용하려면 Cloneable을 구현해야함
그렇지 않으면 CloneNotSupportedException 예외를 던짐
복제가 제대로 이루어지려면 다음의 규약을 만족해야 한다
x.clone() != x
-> 원본 객체와 복사된 객체는 서로 다르다
-> 논리적 동치
x.clone().getClass() == x.getClass()
-> 해당 클래스와 모든 상위 클래스가 super.clone으로 호출하는 관례를 따르면 참임, 반드시 만족해야 하는 것은 아님
x.clone().equals(x)
-> 일반적으로 참, 필수 아님
clone 메서드 재정의할 때 주의사항
모든 필드가 기본 타입이거나 불변 객체를 참조하면 super.clone만 호출하면 됨
클라이언트가 형변환하지 않아도 되게끔 해주자
재정의한 메서드의 반환 타입은 상위 클래스의 메서드가 반환하는 타입의 하위 타입일 수 있다 (공변 반환 타이핑)
-> 가변 객체를 참조하지 않는 경우
클래스가 가변 객체를 참조할 때는?
-> 복제 후에도 원복 객체와 복제본이 모두 같은 배열을 참조하기 때문에 재앙으로 이어질 수 있음
해결 방법
재귀적 호출
-> 배열이 final이면 사용할 수 없음. 경우에 따라, final 한정자를 제거해야 할 수도 있음
재귀적 호출만으로 충분치 않은 경우
-> 복제본은 자신만의 버킷 배열을 갖지만, 배열 안에 있는 연결리스트는 여전히 원본과 같은 것을 참조하고 있음
해결 방법
1.
-> 리스트가 길면 스택 오버플로우가 발생할 위험이 있기 때문에 사용할 수 없음
-
-> 재귀 호출 대신 반복문을 사용해 스택 오버플로우를 피함 -
원본 테이블의 put(key, value) 메서드를 호출해 같은 내용의 bucket을 만들어 복제하는 방법
-> 속도가 느림
하위 클래스에서 재정의될 메서드를 호출하면 안된다
public class Sup implements Cloneable{
String type;
public Sup() {
this.type = "super";
}
public void overrideMe() {
System.out.println("super method");
}
@Override
public Sup clone() {
try {
overrideMe();
return (Sup) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException();
}
}
}
public class Sub extends Sup {
String temp;
@Override
public void overrideMe() {
System.out.println("sub mehtod");
System.out.println(temp);
type = "sub";
}
@Override
public Sub clone() {
Sub clone = (Sub) super.clone();
clone.temp = "temp";
return clone;
}
}
(출처 - https://javabom.tistory.com/15)
상속해서 쓰기 위한 클래스는 Cloneable을 구현하면 안된다
아직 cloneable을 구현한 클래스가 아니라면 복사 생성자와 복사 팩터리를 사용할 수 있다
-> Cloneable/clone 방식보다 장점이 훨씬 많다
-> 대표적으로 복제본의 타입을 직접 선택할 수 있다
Author And Source
이 문제에 관하여([아이템 13] clone 재정의는 주의해서 진행하라), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@lsjpjs1/아이템-13-clone-재정의는-주의해서-진행하라저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)