2. immutable 클래스
• 자신의 인스턴스가 갖는 값을 변경할 수 없는 클래스
• 각 인스턴스가 갖는 모든 정보는 생성될 때 제공됨
• String, boxed primitive 클래스, BigInteger, BigDecimal, …
• 설계와 구현 및 사용이 더 쉽다.
• 에러 발생이 적고, 보안이나 사용 측면에서 더 안전하다.
3. immutable 클래스 구현 규칙
1. 객체의 상태를 변경하는 메소드(mutator)를 제공하지 않
는다.
2. 상속 할 수 없다.
3. 모든 필드는 final로 지정한다.
4. 모든 필드는 private로 지정한다.
5. mutable 컴포넌트의 직접적인 외부 접근을 막자.
4. immutable 객체의 장점
• Simple
– 생성자에서 불변성을 확립하고 함수적 방법(functional access)으
로
메소드를 작성한다면 쉽게 불변성을 유지할 수 있다.
• Thread-safe
– 자유롭게 공유가능 → 자주 사용되는 객체 재사용
• public static final 상수 제공
• static factory 메소드로 기존 인스턴스 재사용
• 방어복사본(depensive copies)을 만들 필요 없음
public static final BigInteger ZERO = new BigInteger(new int[0], 0);
public static final BigInteger ONE = valueOf(1);
private static final BigInteger TWO = valueOf(2);
5. immutable 객체의 장점
• 객체 내부 구조도 공유 가능
• 다른 객체를 만들 때 사용하기 좋은 컴포넌트
– 컴포넌트들이 immutable이면 그 객체의 불변성을 지키기 좋다.
public class BigInteger extends Number implements
Comparable<BigInteger> {
final int signum;
final int[] mag;
/* … */
public BigInteger negate() {
return new BigInteger(this.mag, -this.signum);
}
/* … */
}
6. immutable 객체의 단점
• 값마다 별개의 객체가 필요하다!
– 여러 단계의 연산 시 불필요한 객체 생성이 많다.
가변 클래스를 만들어 사용한다.
• BigInteger와 BitSet, String와 StringBuilder
• 내부적으로 privmitives 연산을 수행
7. immutable Class 설계 시 참고점
• 서브 클래스를 만들지 못하게 해야 한다.
– 클래스를 final로 지정
– 생성자를 private(package private)으로 지정하고,
static factory 메소드 이용
• 인스턴스 재사용성
• naming의 유연성
• 반환 타입의 유연성
• parameterized type의 인스턴스 생성 코드의 간결
8. immutable Class 설계 시 참고점
• 서브 클래스를 만들지 못하게 해야 한다.
– BigInteger, BigDecimal의 경우 상속 가능하게 설계 되었음
– Serializable을 구현하면서 mutable 객체를 참조하는 필드를 가진
다면, 반드시 readObject나 readReasolve 메소드를 정의해야 한
다.
(또는 ObjectOutputStream.writeUnshared와
ObjectInputStream.readUnshared 메소드 사용)
public static BigInteger safeInstance(BigInteger val) {
if (val.getClass() != BigInteger.class) {
return new BigInteger(val.toByteArray());
}
return val;
}
9. 요약
• mutable할 타당한 이유가 없다면, 그 클래스는 immutable이 되어야
한다.
• 현실적으로 immutable 클래스가 될 수 없다면, 가능한 가변성을 제한
하자.
– 특별한 이유가 없는 한 모든 필드를 final로 만든다.
• 생성자에서는 모든 불변 규칙이 확립되어 완벽하게 초기화된 객체를
생성해야 한다.
• 특별한 이유가 없다면 생성자나 static 팩토리 메소드 외에 다른
public 초기화 메소드를 두지 않는다.
• 또한 재초기화 메소드도 제공하지 말아야 한다.