열거 형을 사용하여 싱글 톤 구현 (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.