열거 형을 사용하여 싱글 톤 구현 (Java)


178

나는 다음과 같은 것을 Singleton사용하여 Java 로 구현하는 것이 가능하다는 것을 읽었습니다 Enum.

public enum MySingleton {
     INSTANCE;   
}

그러나 위의 작동 방식은 무엇입니까? 구체적으로, Object인스턴스화해야합니다. 여기서 어떻게 MySingleton인스턴스화되고 있습니까? 누가하고 new MySingleton()있니?


24
누가 새로운 MySingleton ()을하고 있습니까 ?
Sotirios Delimanolis

37
INSTANCE와 동일합니다 public static final MySingleton INSTANCE = new MySingleton();.
Pshemo

6
ENUM-보장 된 싱글 톤.
버그 아님

dzone.com/articles/java-singletons-using-enum을 읽으십시오 . 다른 방법이 아닌 enum을 사용해야하는 이유. 짧게 : 직렬화 및 반사를 사용할 때 문제가 시작됩니다.
미야기

답변:


203

이,

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유형의 인스턴스입니다 . 그리고 열거 형이 처음 참조 될 때 구성됩니다 .


13
기본적으로 열거 형에는 암시 적 개인 생성자가 있고 해당 생성자에서 실제로 실행해야하는 코드가 없으면 명시 적으로 개인 생성자를 추가 할 필요가 없습니다.
Nimrod Dayan

각 열거 형 필드는 인스턴스를 한 번만 생성하므로 개인 생성자를 만들 필요가 없습니다.
Pravat Panda

2
공개 열거 형 MySingleton {INSTANCE, INSTANCE1; } 그런 다음 System.out.println (MySingleton.INSTANCE.hashCode ()); System.out.println (MySingleton.INSTANCE1.hashCode ()); 다른 해시 코드를 인쇄합니다. MySingleton의 두 개체가 생성되었다는 의미입니까?
scott miles

@scottmiles 예. 두 개의 인스턴스가 있기 때문입니다. 정의에 따르면 싱글 톤에는 하나가 있습니다.
Elliott Frisch

private수정은 아무 의미가없는 enum생성자와 완전히 중복됩니다.
Dmitri Nesteruk

76

enum유형의 특별한 유형입니다 class.

당신의 enum사실은 실제로 다음과 같이 컴파일됩니다

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

코드가 처음 액세스 하면 JVM INSTANCE이 클래스 MySingleton를로드하고 초기화합니다. 이 프로세스는 static위 의 필드를 한 (지연하게) 초기화합니다 .


이 클래스에도 private constructor ()가 포함되어 있습니까? 나는 그것은있을 거라고 생각
시르의 Shabbir Choudhary에게

public enum MySingleton { INSTANCE,INSTANCE1; }그런 다음 System.out.println(MySingleton.INSTANCE.hashCode()); System.out.println(MySingleton.INSTANCE1.hashCode());다른 해시 코드를 인쇄합니다. MySingleton의 두 개체가 생성되었다는 의미입니까?
scott miles

2
@scottmiles 네, 그것은 단지 두 개의 차이 enum상수입니다.
Sotirios Delimanolis

2
@caf, 물론입니다. 여기를 참조하십시오 : docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.9.3
Sotirios Delimanolis

@SotiriosDelimanolis, 열거 형 스레드가있는이 접근법은 안전합니까?
abg

63

Joshua Bloch 의이 Java 모범 사례 책 에서 개인 생성자 또는 Enum 유형으로 Singleton 속성을 적용해야하는 이유를 설명 할 수 있습니다. 이 장은 매우 길기 때문에 요약하여 보관하십시오.

클래스를 Singleton으로 만들면 유형을 제공하는 인터페이스를 구현하지 않는 한 싱글 톤을 모의 구현으로 대체 할 수 없으므로 클라이언트를 테스트하기가 어려울 수 있습니다. 권장되는 접근 방식은 하나의 요소로 열거 형을 간단히 만들어 싱글 톤을 구현하는 것입니다.

// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}

이 방법은보다 간결하고 직렬화 기계를 무료로 제공하며 정교한 직렬화 또는 리플렉션 공격에도 불구하고 다중 인스턴스화에 대한 확실한 보장을 제공한다는 점을 제외하고는 공공 현장 접근 방식과 기능적으로 동일합니다.

이 방법은 아직 널리 채택되지 않았지만 단일 요소 열거 형 유형이 단일 톤을 구현하는 가장 좋은 방법입니다.


싱글 톤을 테스트 할 수있게하려면 전략 패턴을 사용하고 모든 싱글 톤의 동작이 전략을 거치게 할 수 있다고 생각합니다. 따라서 하나의 "생산"전략과 하나의 "테스트"전략을 가질 수 있습니다.
Erk

9

모든 열거 형 인스턴스와 마찬가지로 Java는 클래스가로드 될 때 각 객체를 인스턴스화하며 JVM 마다 정확히 한 번 인스턴스화되도록 보장합니다 . 생각INSTANCE선언을 공개 정적 최종 필드로 . Java는 클래스가 처음 참조 될 때 오브젝트를 인스턴스화합니다.

인스턴스는 정적 초기화 중에 작성되는데, 이는 Java 언어 스펙, 섹션 12.4에 정의되어 있습니다.

가치가있는 것에 대해 Joshua Bloch 는이 패턴을 Effective Java Second Edition 의 항목 3으로 자세히 설명합니다 .


6

Singleton Pattern 은 개인 생성자를 가지고 인스턴스화를 제어하기 위해 몇 가지 메소드를 호출하는 것과 관련이 있기 때문에 (일부처럼 getInstance) Enums에는 이미 암시 적 개인 생성자가 있습니다.

JVM 또는 일부 컨테이너 가 어떻게 우리 인스턴스를 제어 하는지 알지 Enums못하지만 이미 암시 적 Singleton Pattern인 것을 사용하는 것 같습니다 . 차이점은 우리가 전화하지 않고 getInstanceEnum이라고 부르는 것입니다.


3

앞에서도 언급했듯이, 열거 형은 그 정의가 적어도 하나의 "열상 수"로 시작해야한다는 특수한 조건을 가진 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 키워드 등으로 처리해야한다는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.