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 이외 클래스 상속 시 사용 불가