Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

item13 - clone 재정의는 주의해서 진행하라 

...


메서드 하나 없는 Clonable 인터페이스는 무얼하나?


놀랍게도 Object의 protected 메서드인 clone의 동작 방식을 결정한다.


clone 메서드의 일반 규약 (허술함)


객체의 복사본을 생성해 반환한다.


Clone 메서드는 사실상 생성자와 같은 효과를 낸다. 즉, clone은 원본 객체에 아무런 해를 끼치지 않는 동시에 복제된 객체의 불변식을 보장해야 한다.


요약하자면..


Cloneable을 구현하는 모든 클래스는 clone을 재정의하고 동기화해야한다. -> 객체의 내부 '깊은 구조'에 숨어 있는 모든 가변 객체를 복사하고, 복제본이 가진 객체 참조 모두가 복사된 객체들을 가리키게 한다.

how? 주로 clone을 재귀적으로 호출해 구현하지만 항상 최선은 아니다.


item14 - Comparable을 구현할지 고려하라


[4장 클래스와 인터페이스]

추상화의 기본 단위인 클래스와 인터페이스는 자바 언어의 심장!! 그 설계에 사용하는 강력한 요소가 많이 있다.

...

  • 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않는다.
  • 클래스를 확장할 수 없도록 한다.
  • 모든 필드를 final로 선언한다.
  • 모든 필드를 private으로 선언한다.
  • 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.

클래스를 확장 할 수 없도록 하는 다른 방법 : 모든 생성자를 private 혹은 package-private으로 만들고public정적 팩터리를 제공하는 방법

public final class Complex {
    private final double re;
    private final double im;

    public static final Complex ZERO = new Complex(0, 0);
    public static final Complex ONE  = new Complex(1, 0);
    public static final Complex I    = new Complex(0, 1);

    public Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }

    public double realPart()      { return re; }
    public double imaginaryPart() { return im; }

    // 주목할 부분 두가지
    public Complex plus(Complex c) {  // 동사 add가 아닌 전치사 plus 사용
        // 사칙연산 메서드들이 인스턴스 자신은 수정하지 않고 새로운 Complecx 인스턴스를 만들어 반환하는 모습 주목
        return new Complex(re + c.re, im + c.im);
    }

    // 코드 17-2 정적 팩터리(private 생성자와 함께 사용해야 한다.) (110-111쪽)
    public static Complex valueOf(double re, double im) {
        return new Complex(re, im);
    }

    public Complex minus(Complex c) {
        return new Complex(re - c.re, im - c.im);
    }

    public Complex times(Complex c) {
        return new Complex(re * c.re - im * c.im,
                re * c.im + im * c.re);
    }

    public Complex dividedBy(Complex c) {
        double tmp = c.re * c.re + c.im * c.im;
        return new Complex((re * c.re + im * c.im) / tmp,
                (im * c.re - re * c.im) / tmp);
    }

    @Override public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Complex))
            return false;
        Complex c = (Complex) o;

        // == 대신 compare를 사용하는 이유는 63쪽을 확인하라.
        return Double.compare(c.re, re) == 0
                && Double.compare(c.im, im) == 0;
    }
    @Override public int hashCode() {
        return 31 * Double.hashCode(re) + Double.hashCode(im);
    }

    @Override public String toString() {
        return "(" + re + " + " + im + "i)";
    }
}

...