public final class Complex {
private final double re;
private final double im;
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 o) {
return new Complex(re + o.re, im + o.im);
}
public Complex minus(Complex o) {
return new Complex(re - o.re, im - o.im);
}
public Complex times(Complex o) {
return new Complex(re * o.re - im * o.im, re * o.im + im * o.re);
}
public Complex dividedBy(Complex o) {
double tmp = o.re * o.re + o.im + o.im;
return new Complex((re * o.re + im * o.im) / tmp,(im * o.re - re * o.im) / tmp);
}
@Override
public boolean equals(Object o) {
if ( o == this) {
return true;
}
if (!(o instanceof Complex)) {
return false;
}
Complex c = (Complex)o;
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";
}
}
myBatis나 jackson을 쓰기 위해서는 final로 쓸 수 없음. 기본 생성자를 요구하기 때문!
장점
근본적으로 thread safe, 안심하고 공유할 수 있다.
불변객체끼리는 내부 데이터를 공유 할 수 있다.
public class BigInteger extends Number implements Comparable<BigInteger> {
final int signum;
final int[] mag;
...
public BigInteger negate() {
return new BigInteger(this.mag, -this.signum);
}
...
}
불변 객체는 그 자체로 실패 원자성을 제공한다. (실패원자성 : 예외가 발생한 이후에도, 그 객체는 여전히 동일한 상태)
단점
값이 다르면 반드시 독립된 개체로 만들어야 한다.
이를 해결하기 위해 가변동반클래스를 제공 : String - StringBuilder
불변 클래스를 만드는 다른 방법
public class Complex {
private final double re;
private final double im;
private Complex(double re, double im) {
this.re = re;
this.im = im;
}
public static Complex valueOf(double re, double im) {
return new Complext(re, im);
}
...
}
다양한 유연성을 제공한다. (예를들어 값을 캐쉬하거나 할 수 있다)
그외 참고
final 이 아닌 불변객체를 의심되는 클라이언트로부터 받았을때에는 방어적 복사본(#50)을 사용하라. -> 어차피 reflextion때문에 소용없는거 아님?
불변 클래스의 특정값이 계산이 오래 걸린다면 지연 초기화(#83)을 할 수 있다. PhoneNumber의 hachCode(#11)이 그러한 형식이다.
불변객체를 만드는 다섯가지 규칙
장점
단점
불변 클래스를 만드는 다른 방법
그외 참고
최종 정리