Skip to content

Latest commit

 

History

History
132 lines (98 loc) · 3.9 KB

13.clone 재정의는 주의해서 진행.md

File metadata and controls

132 lines (98 loc) · 3.9 KB

Cloneable

- **복제해도 되는 클래스**임을 명시
- 구현(implements)하지 않고 `clone()` 메소드 사용 시 `CloneNotSupportedException`
- 구현 후 `clone()` 호출 시 객체의 필드를 하나하나 복사한 객체 반환

Clone

전제조건


상위 클래스가 제대로 동작하는 clone 메서드를 가지며 Cloneable을 구현해줄 때

모든 필드가 기본 타입 / 불변 타입


  • 상위 객체의 clone() 메서드를 호출

    • 바로 원본의 복사본을 얻을 수 있다.

    오버라이딩

    • 리턴 타입부모 메소드의 리턴 타입의 자식인 경우 리턴 타입을 변경 가능하다.
      • Object에서는 Object 타입을 리턴해 준다.
      • Crew 클래스에서는 편의를 위해 Crew 타입을 리턴하도록 변경
    • 부모 메소드의 접근제한자를 확장 가능하다.
      • Object에서는 protected로 선언되어 있다.
      • Crew 클래스에서는 clone()를 모두 사용할 수 있도록 public 제한자로 변경
class Crew implements Cloneable{
    String course;
    String name;

    public Crew(String course, String name) {
        this.course = course;
        this.name = name;
    }

    @Override
    public Crew clone() {
        try {
            return (Crew)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

참조 필드가 존재하는 경우

  • 문제점

    Clone()의 결과로 같은 객체를 참조하게 되어 문제 발생

  • 해결 방안

    • 상위 객체의 clone() 메서드를 호출
    • 참조 필드에 대해서 복사 진행
int[] numbers;

...

@Override
public Lotto clone() {
    try {
        Lotto clonedLotto = (Lotto)super.clone();
        clonedLotto.numbers = numbers.clone();
        return clonedLotto;
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
        return null;
    }
}
  • 복사 생성자 / 복사 팩터리

    • 자신과 같은 클래스의 인스턴스를 인수로 받는 생성자 / 메서드
    public Lotto() {
            numbers = new int[]{1, 2, 3, 4, 5, 6};
    }
    
    // 복사 생성자
    public Lotto(Lotto lotto) {
    // 매개변수에 있는 lotto의 값들로 현재 인스턴스를 채워준다.
        super();
        setLotto(lotto.numbers);
    }
    
    // 복사 팩터리
    public static Lotto newInstance(Lotto lotto) {
    // 매개변수에 있는 lotto의 값들로 채워진 인스턴스를 반환
        Lotto instance = new Lotto();
        instance.setLotto(lotto.numbers); 
        return instance;
    }
    
    public void setLotto(int[] targetNumbers) {
        for (int i = 0; i < 6; i++) {
            numbers[i] = targetNumbers[i];
        }
    }
  • 인터페이스 타입의 인스턴스를 인수로 받을 수 있다는 장점이 있다.

    • Collection 변환에 사용된다.
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4);
        List<Integer> arrayList = new ArrayList<>(list); // 복사 생성자
    }

핵심 정리

기본 원칙으로는 복제 기능은 생성자와 팩터리를 이용하는 것이 가장 좋으며, 배열의 경우는 예외로 clone 메서드가 가장 깔끔하다.

참고 자료

[https://velog.io/@roro/Java-Object-클래스-clone](https://velog.io/@roro/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4-clone)

[https://blog.geunho.dev/posts/java-deep-copy-shallow-copy/](https://blog.geunho.dev/posts/java-deep-copy-shallow-copy/)

[https://bitsoul.tistory.com/55](https://bitsoul.tistory.com/55)