나는 다음과 같은 것을 Singleton
사용하여 Java 로 구현하는 것이 가능하다는 것을 읽었습니다 Enum
.
public enum MySingleton {
INSTANCE;
}
그러나 위의 작동 방식은 무엇입니까? 구체적으로, Object
인스턴스화해야합니다. 여기서 어떻게 MySingleton
인스턴스화되고 있습니까? 누가하고 new MySingleton()
있니?
답변
이,
public enum MySingleton {
INSTANCE;
}
암시 적 빈 생성자가 있습니다. 대신 명시 적으로 작성하십시오.
public enum MySingleton {
INSTANCE;
private MySingleton() {
System.out.println("Here");
}
}
그런 다음과 같은 main()
방법으로 다른 클래스를 추가 한 경우
public static void main(String[] args) {
System.out.println(MySingleton.INSTANCE);
}
당신은 볼 것이다
Here
INSTANCE
enum
필드는 컴파일 시간 상수이지만 해당 enum
유형의 인스턴스입니다 . 그리고 열거 형이 처음 참조 될 때 구성됩니다 .
답변
enum
유형의 특별한 유형입니다 class
.
당신의 enum
사실은 실제로 다음과 같이 컴파일됩니다
public final class MySingleton {
public final static MySingleton INSTANCE = new MySingleton();
private MySingleton(){}
}
코드가 처음 액세스 하면 JVM INSTANCE
이 클래스 MySingleton
를로드하고 초기화합니다. 이 프로세스는 static
위 의 필드를 한 번 (지연하게) 초기화합니다 .
답변
Joshua Bloch 의이 Java 모범 사례 책 에서 개인 생성자 또는 Enum 유형으로 Singleton 속성을 적용해야하는 이유를 설명 할 수 있습니다. 이 장은 매우 길기 때문에 요약하여 보관하십시오.
클래스를 Singleton으로 만들면 유형을 제공하는 인터페이스를 구현하지 않는 한 싱글 톤을 모의 구현으로 대체 할 수 없으므로 클라이언트를 테스트하기가 어려울 수 있습니다. 권장되는 접근 방식은 하나의 요소로 열거 형을 간단히 만들어 싱글 톤을 구현하는 것입니다.
// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}
이 방법은보다 간결하고 직렬화 기계를 무료로 제공하며 정교한 직렬화 또는 리플렉션 공격에도 불구하고 다중 인스턴스화에 대한 확실한 보장을 제공한다는 점을 제외하고는 공공 현장 접근 방식과 기능적으로 동일합니다.
이 방법은 아직 널리 채택되지 않았지만 단일 요소 열거 형 유형이 단일 톤을 구현하는 가장 좋은 방법입니다.
답변
모든 열거 형 인스턴스와 마찬가지로 Java는 클래스가로드 될 때 각 객체를 인스턴스화하며 JVM 마다 정확히 한 번 인스턴스화되도록 보장합니다 . 생각INSTANCE
선언을 공개 정적 최종 필드로 . Java는 클래스가 처음 참조 될 때 오브젝트를 인스턴스화합니다.
인스턴스는 정적 초기화 중에 작성되는데, 이는 Java 언어 스펙, 섹션 12.4에 정의되어 있습니다.
가치가있는 것에 대해 Joshua Bloch 는이 패턴을 Effective Java Second Edition 의 항목 3으로 자세히 설명합니다 .
답변
Singleton Pattern 은 개인 생성자를 가지고 인스턴스화를 제어하기 위해 몇 가지 메소드를 호출하는 것과 관련이 있기 때문에 (일부처럼 getInstance
) Enums에는 이미 암시 적 개인 생성자가 있습니다.
JVM 또는 일부 컨테이너 가 어떻게 우리 인스턴스를 제어 하는지 알지 Enums
못하지만 이미 암시 적 Singleton Pattern
인 것을 사용하는 것 같습니다 . 차이점은 우리가 전화하지 않고 getInstance
Enum이라고 부르는 것입니다.
답변
앞에서도 언급했듯이, 열거 형은 그 정의가 적어도 하나의 “열상 수”로 시작해야한다는 특수한 조건을 가진 Java 클래스입니다.
그 외에는 열거 형을 확장하거나 다른 클래스를 확장하는 데 사용할 수 없으므로 열거 형은 모든 클래스와 같은 클래스이며 상수 정의 아래에 메소드를 추가하여 사용합니다.
public enum MySingleton {
INSTANCE;
public void doSomething() { ... }
public synchronized String getSomething() { return something; }
private String something;
}
다음 행을 따라 싱글 톤의 메소드에 액세스하십시오.
MySingleton.INSTANCE.doSomething();
String something = MySingleton.INSTANCE.getSomething();
클래스 대신 열거 형을 사용하는 것은 다른 답변에서 언급했듯이 대부분 싱글 톤의 스레드 안전 인스턴스화와 항상 하나의 사본 만 보장한다는 것입니다.
그리고 가장 중요한 것은이 동작이 JVM 자체와 Java 사양에 의해 보장된다는 것입니다.
다음 은 열거 형 인스턴스의 여러 인스턴스를 방지하는 방법에 대한 Java 사양 섹션입니다 .
열거 형에는 열거 형 상수로 정의 된 인스턴스 이외의 인스턴스가 없습니다. 열거 형 유형을 명시 적으로 인스턴스화하려고 시도하면 컴파일 타임 오류입니다. Enum의 최종 복제 방법을 사용하면 열거 상수를 복제 할 수 없으며 직렬화 메커니즘에 의한 특수 처리를 통해 역 직렬화의 결과로 중복 인스턴스가 생성되지 않습니다. 열거 형 유형의 반사 인스턴스화는 금지됩니다. 이 네 가지가 함께 있으면 열거 형 상수에 의해 정의 된 것 이상의 열거 형 인스턴스가 존재하지 않습니다.
주목할만한 점은 인스턴스화 후 thread 안전 문제는 다른 키워드와 마찬가지로 synchronized 키워드 등으로 처리해야한다는 것입니다.