본문 바로가기
책 정리/이펙티브 자바

[이펙티브 자바] private 생성자나 열거 타입으로 싱글턴임을 보증하라 - item 3

by chanwoodev 2023. 6. 20.

public static final 필드 방식의 싱글턴

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }

    public void leaveTheBuilding() { ...}

}
  • privte 생성자는 INSTANCE를 초기화 할 때 딱 한번만 호출된다.
  • pubilc이나 protected 생성자가 없으므로 싱글턴임을 보장한다.
  • 리플렉션을 사용해 private을 호출하는 경우 싱글턴을 깨뜨릴 수 있는데 생성자 두번 호출 시 예외를 반환하도록 하면 된다.

해당 방식의 장점

  • 해당 클래스가 싱글턴임이 API에 드러난다

정적 팩토리 방식의 싱글턴

public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() {...}
    public static Elvis getInstatce() { return INSTANCE; }

    public void leaveTheBuilding() { ... }
}

해당 방식의 장점

  • 싱글턴이 아니도록 메서드를 수정할 수 있다
  • 원한다면 정적 팩토리를 제네릭 싱글턴 팩토리로 만들 수 있다

 

싱글턴을 직렬화하려면?

 

단순히 Serailizable을 구현하면 직렬화된 인스턴스를 역직렬화 할 때마다 새로운 인스턴스가 만들어짐

  • 모든 인스턴스 필드-> transient로 선언하고 readResolve메서드로 컨트롤해주어야한다.
public Objcet readResolve() {
	return INSTANCE;
}

transient를 필드에 설정하면 직렬화, 역직렬화에서 제외된다.

역직렬화 시 readResolve 메서드의 반환 값으로 대체된다.

추천 글: readResolve와 writeReplace

 

열거 타입 방식의 싱글턴

public enum Elvis {
	INSTANCE;

	public void ...
}

 

  • public 필드 방시과 비슷하지만, 더 간결하고 직렬화 상황, 리플렉션 공격에도 싱글턴을 보장한다.
  • 부분 상황에서 원소가 하나뿐인 열거 타입이 싱글턴을 만드는 가장 좋은 방법
  • 단, 만드려는 싱글턴이 Enum 이외 클래스 상속 시 사용 불가