공개 정적 최종 필드가있는 클래스와 Java 열거의 장점은 무엇입니까?


147

C #에 익숙하지만 Java에서 더 많은 작업을 시작합니다. Java의 열거 형은 기본적으로 C #의 열거 형과 동일하지만 실제로는 그렇지 않습니다. 처음에는 Java 열거 형에 매우 유리한 여러 조각의 데이터가 포함될 수 있음을 알게되어 기뻤습니다 ( http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html ). 그러나 그 이후로 열거 형 요소에 특정 값을 쉽게 할당 할 수있는 능력과 적절한 노력없이 정수를 열거 형으로 변환하는 기능과 같이 C #에서 사소한 많은 기능이 누락되었습니다. 즉 정수 값을 일치하는 Java Enum으로 변환하십시오 .

그래서 내 질문은 이것입니다 : 많은 공개 정적 최종 필드가있는 클래스에 비해 Java 열거에 이점이 있습니까? 아니면 더 간단한 구문을 제공합니까?

편집 : 더 명확하게하겠습니다. 같은 유형 의 공개 정적 최종 필드 많은 클래스에 비해 Java 열거 형의 이점은 무엇입니까 ? 예를 들어 첫 번째 링크의 행성 예에서 다음과 같은 공용 상수를 사용하는 클래스보다 열거 형의 장점은 무엇입니까?

public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6);
public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6);
public static final Planet MARS = new Planet(6.421e+23, 3.3972e6);
public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7);
public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7);
public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7);
public static final Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);

내가 알 수있는 한, casablanca의 대답은 이것을 충족시키는 유일한 것입니다.


4
@Bohemian : OP는 public static final필드 만 언급했기 때문에 중복되지 않을 수 있습니다. 필드는 값이 입력 될 수 있으며 반드시 ints 일 필요는 없습니다 .
casablanca

1
@Shahzeb 거의. 문자열 상수 대신 열거 형을 사용하는 것은 매우 좋은 아이디어이며 권장되는 것 이상입니다. 타입 안전, 정적 유틸리티 기능 등이 필요하지 않습니다. 대신 문자열을 사용할 이유가 없습니다.
Voo

1
@Voo 예, 의견 차이가있을 것입니다. 그리고 여기에 49 초가 걸립니다. 열거 형은 훌륭합니다 (그리고 그들을 사랑하고 자주 사용합니다). 상수를 선언하거나 사용할 때 어떤 유형의 안전이 필요합니까? String literal의 상수를 선언해야 할 때마다 열거 형을 만드는 것은 과잉입니다.
Shahzeb

4
@Shahzeb 단일 변수가있는 경우 문자열을 사용해야합니다. 여기서는 많이 발생하지 않습니다 (단일 값은 매개 변수로 의미가 없습니다). 그러나 constant S에 대해 이야기하고 있으므로 이제 함수에 함수 등을 전달하는 것에 대해 이야기하고 있습니다. type-saftey 가 필요 합니까? 그러나 대부분의 사람들은 c 스타일 유형의 "모든 것이 void*좋은 스타일"이라고 생각하며 버그를 막을 수 있습니다 (특히 하나 이상의 열거 형 / 문자열 매개 변수를 전달하는 경우). 또한 상수를 자체 네임 스페이스 등에 넣습니다. 이와 달리 일반 변수 만 갖는 것이 실제로 이점은 없습니다.
Voo

3
@ 보헤미안 : 어떻게 보지 못합니다. ints를 사용하면 값을 전달할 수 있기 때문에 형식 안전성이 없습니다. 반면에 유형이 지정된 객체는 유형 안전성 측면에서 열거 형과 다르지 않습니다.
casablanca

답변:


78

기술적으로 열거 형을 여러 유형의 상수가있는 클래스로 볼 수 있으며 실제로는 열거 형 상수가 내부적으로 구현되는 방식입니다. enum그러나를 사용 하면와 같이 스스로 구현 해야하는 유용한 메소드 ( Enum javadoc )가 제공됩니다 Enum.valueOf.


14
또한 .values()값 목록을 반복해야합니다.
h3xStream

1
만족 스럽지는 않지만 올바른 답변 인 것 같습니다. 내 의견으로는 Java가 더 간단한 구문과 Enum 메소드에 대한 액세스를 위해 열거 형에 대한 지원을 추가하는 것은별로 가치가 없다.
Craig W

7
@ 당신의 본능이 옳다고 생각하십시오-이것은 열거 형의 목적을 완전히 놓 쳤기 때문에 매우 나쁜 대답입니다. 이유의 일부에 대해서는 질문 아래 내 의견을 참조하십시오.
보헤미안

1
@Bohemian : 나는 열거 형의 "목적을 그리워하지"않았다. 나는 항상 그것들을 사용한다. 위의 의견에 대한 내 답변을 참조하십시오.
casablanca

1
Enum.valuesOf 메소드는 두 번 호출하면 동일한 객체를 반환합니까?
Emre Aktürk

104
  1. 안전 및 가치 안전을 입력하십시오.
  2. 싱글 톤 보장.
  3. 메소드를 정의하고 대체하는 기능.
  4. 의 값을 사용할 수있는 기능 switchcase자격없이 문을.
  5. 다음을 통한 값의 내장 순차 ordinal().
  6. 가치가 아닌 이름으로 직렬화하여 미래를 보장합니다.
  7. EnumSet그리고 EnumMap수업.

19
모든 것을 말했지만, Enum에 코드를 넣을 때마다 후회했습니다.
Lorne의 후작

4
왜 후회 했어? 나는 결코…
glglgl

2
@glglgl 응용 프로그램 별 코드를 실제로 속하지 않은 곳으로 가져 갔기 때문에 실제로는 값 집합 만 정의하는 것이 었습니다. 다시해야한다면, 그것을 switch사용하는 원래 동기였던 수많은 진술 중 하나에 포함했을 것 Enum입니다.
Lorne의 후작

72

아무도 switch진술 에서 그것들을 사용할 수있는 능력을 언급하지 않았다 . 나는 그것을 넣을 것이다.

이것은 임의로 복잡한 열거 형을 사용하여 instanceof잠재적으로 혼란스러운 if시퀀스 또는 문자열이 아닌 / int 스위칭 값 을 사용하지 않고 깨끗한 방식으로 사용할 수 있습니다 . 표준 예는 상태 머신입니다.


어쨌든 열거 형 필드와 정적 필드의 이점을 언급하지 않았으므로 정적 필드가있는 switch 문에 충분한 유형을 사용할 수 있습니다. Op 실제 기능 또는 성능 차이가 필요
Genaut

@Genaut 이점은 열거 형이 문자열보다 더 많은 기능을 가지고 있다는 것입니다. 문제는 내가 제공 한 차이점에 관한 것입니다. OP는 이미 열거 형이 무엇인지 알고 있으며 4.5 년 전에이 게시물을 게시했을 때 아무도 스위치 진술을 언급하지 않았으며 적어도 몇 사람이 새로운 정보를 제공하는 것을 발견했습니다. ¯_ (ツ) _ / ¯
Dave Newton

44

주요 장점은 형식 안전성입니다. 상수 세트를 사용하면 동일한 내장 유형의 모든 값을 사용하여 오류가 발생할 수 있습니다. 열거 형을 사용하면 적용 가능한 값만 사용할 수 있습니다.

예를 들어

public static final int SIZE_SMALL  = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE  = 3;

public void setSize(int newSize) { ... }

obj.setSize(15); // Compiles but likely to fail later

vs

public enum Size { SMALL, MEDIUM, LARGE };

public void setSize(Size s) { ... }

obj.setSize( ? ); // Can't even express the above example with an enum

3
클래스는 타입이 안전합니다 ... : / (정적 필드가 컨테이너 클래스의 타입이라고 가정)
h3xStream

여전히 유효하지 않은 값을 전달할 수는 있지만 훨씬 쉽게 발견 할 수있는 컴파일 시간 오류입니다.
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

2
setSize(null)두 번째 예제를 호출 할 수 있지만 첫 번째 예제의 오류보다 훨씬 빨리 실패 할 수 있습니다.
Jeffrey

42

혼란이 적습니다. Font예를 들어 보자 . Font원하는 이름 , 크기 및 스타일 ( new Font(String, int, int)) 을 갖는 생성자가 있습니다. 오늘날까지 스타일이나 크기가 먼저되는지 기억이 나지 않습니다. 경우 Font사용했다 enum그것의 다른 스타일의 모든을 ( PLAIN, BOLD, ITALIC, BOLD_ITALIC), 생성자는 같을 것이다 Font(String, Style, int)혼란을 방지. 불행히도 클래스가 만들어 enum졌을 때 s는 없었고 FontJava는 역 호환성을 유지해야하기 때문에 항상이 모호함에 시달릴 것입니다.

물론 이것은 상수 enum대신에 사용하는 인수 일뿐 public static final입니다. 열거 형은 싱글 톤에 적합 하며 기본 동작을 구현하면서 나중에 사용자 정의 할 수 있습니다 (IE 전략 패턴 ). 후자의 예는 다음 java.nio.file의 ' OpenOptionStandardOpenOption개발자가 자신이 아닌 표준을 만들려는 경우 :은 OpenOption, 그가 할 수.


동일한 열거 형 중 두 개가 요청 된 경우 '글꼴'사례는 여전히 모호합니다. 이 문제에 대한 정식 답변은 많은 언어에서 명명 된 매개 변수라고하는 것 입니다. 그보다 나은 IDE 메소드 서명 지원.
aaaaaa

1
@aaaaaa 나는 생성자가 varargs 또는 a 를 enum사용하지 않고 두 개를 사용하여 임의의 수를 취하는 많은 경우를 보지 못했습니다 . Set
Jeffrey

@aaaaaa 명명 된 매개 변수의 주요 문제는 구현 세부 정보 (매개 변수 이름)에 의존합니다. 나는 인터페이스를 만들 수 있습니다 interface Foo { public void bar(String baz); }. 누군가가 호출하는 클래스를 만든다 bar: someFoo.bar(baz = "hello");. 의 서명을 Foo::bar로 변경합니다 public void bar(String foobar). 이제 전화 someFoo를 건 사람은 여전히 작동하려면 코드를 수정해야합니다.
Jeffrey

열거 형 유형이 연속되는 것을 기억하지는 않지만 일반적인 유형은 DAY_OF_WEEK 또는 이와 유사한 것으로 생각했습니다. 인터페이스에 대한 좋은 점은 생각하지 못했습니다. 개인적으로 나는 명명되지 않은 매개 변수로 인한 광범위한 모호성에 대해이 문제를 해결하고 더 강력한 IDE 지원이 필요합니다. 그러나 이것은 판단 요청이며 API 변경을 깨는 것은 진지하게 고려해야 할 사항이라는 것을 알고 있습니다.
aaaaaa

26

여기에는 많은 좋은 대답이 있지만 열거 형을 위해 특별히 Collection API 클래스 / 인터페이스의 구현고도로 최적화 되었다는 언급은 없습니다 .

이 열거 형 특정 클래스는 Enum인스턴스 만 허용 합니다 ( EnumMap유일하게 허용 함)Enum 하고 (키로 ) 가능할 때마다 구현시 간결한 표현 및 비트 조작으로 되돌아갑니다.

이것은 무엇을 의미 하는가?

우리의 Enum타입이 64 개 이하의 요소를 가지고 있지 않다면 (실제 Enum예제의 대부분 이 이것에 적합 할 것입니다), 구현은 요소를 단일 long값으로 저장합니다 Enum. 문제의 각 인스턴스는이 64 비트 길이의 비트와 연관됩니다 long. 에 요소를 추가하는 EnumSet것은 단순히 적절한 비트를 1로 설정하는 것입니다. 제거하는 것은 해당 비트를 0으로 설정하는 것입니다. 요소가 있는지 테스트하는 Set것은 하나의 비트 마스크 테스트입니다! 이제 당신 Enum은 이것을 사랑해야 합니다!


1
전에이 두 가지에 대해 알고 있었지만 방금 What does this mean?섹션 에서 많은 것을 배웠습니다 . 저는 64 사이즈로 구현에 차이가 있다는 것을 알았지 만 실제로 이유를 알지 못했습니다.
Christopher Rucinski

15

예:

public class CurrencyDenom {
   public static final int PENNY = 1;
 public static final int NICKLE = 5;
 public static final int DIME = 10;
public static final int QUARTER = 25;}

자바 상수의 제한

1) 형식 안전 없음 : 우선 형식 안전 이 아닙니다. 유효한 int 값을 int에 지정할 수 있습니다 (예 : 99) 해당 값을 나타내는 동전이 없습니다.

2) 의미없는 인쇄 :이 상수 중 하나를 인쇄하면 의미있는 동전 이름 대신 숫자 값이 인쇄됩니다. 예를 들어 NICKLE을 인쇄하면 "NICKLE"대신 "5"가 인쇄됩니다.

3) 네임 스페이스 없음 : currencyDenom 상수에 액세스하려면 PENNY를 사용하는 대신 클래스 이름 앞에 CurrencyDenom.PENNY를 접두사로 지정해야하지만 JDK 1.5에서 정적 가져 오기를 사용하여 수행 할 수도 있습니다

열거 형의 장점

1) Java의 열거 형은 형식이 안전하며 자체 네임 스페이스가 있습니다. 아래 예의 열거 형에는 예를 들어 "통화"와 같은 유형이 있으며 열거 형 상수에 지정된 값 이외의 값은 할당 할 수 없습니다.

public enum Currency {PENNY, NICKLE, DIME, QUARTER};

Currency coin = Currency.PENNY; coin = 1; //compilation error

2) Java의 Enum은 클래스 또는 인터페이스와 같은 참조 유형이며 Java Enum 유형의 다음 예에 표시된 것처럼 C 및 C ++의 Enum보다 강력한 Enum 내에서 생성자, 메소드 및 변수를 정의 할 수 있습니다.

3) 아래 예제와 같이 생성시 열거 형 상수 값을 지정할 수 있습니다. public enum Currency {PENNY (1), NICKLE (5), DIME (10), QUARTER (25)}; 그러나 이것이 작동하려면 PENNY (1)이 실제로 int value를 허용하는 생성자를 호출하기 때문에 멤버 변수와 생성자를 정의해야합니다 (아래 예 참조).

public enum Currency {
    PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
    private int value;

    private Currency(int value) {
            this.value = value;
    }
}; 

참조 : https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html


11

이미 알고 있듯이 열거 형의 첫 번째 이점은 구문 단순성입니다. 그러나 열거 형의 주요 요점은 기본적으로 범위를 형성하고 유형 및 값 안전 ​​검사를 통해보다 포괄적 인 코드 분석을 수행하는 데 도움이되는 잘 알려진 상수 세트를 제공하는 것입니다.

열거 형의 이러한 특성은 프로그래머와 컴파일러 모두에 도움이됩니다. 예를 들어 정수를받는 함수가 있다고 가정 해 봅시다. 그 정수는 무엇을 의미할까요? 어떤 종류의 가치를 전달할 수 있습니까? 당신은 정말로 바로 알지 못합니다. 그러나 열거 형을 받아들이는 함수가 있으면 전달할 수있는 모든 값을 잘 알고 있습니다.

컴파일러의 경우 열거 형은 값의 범위를 결정하는 데 도움이되며 열거 형 멤버에 특수한 값을 할당하지 않으면 범위가 0 이상입니다. 이를 통해 유형 안전 점검 등을 통해 코드의 오류를 자동으로 추적 할 수 있습니다. 예를 들어, 컴파일러는 switch 문에서 가능한 모든 열거 형 값을 처리하지 않는다고 경고 할 수 있습니다 (예 :default 대소 문자 N 열거 형 값 중 하나만 처리하는 경우). 열거 형의 값 범위가 정수보다 작고 실제로 정수를 허용하지 않는 함수에서 오류가 발생할 수 있기 때문에 임의의 정수를 열거 형으로 변환 할 때 경고합니다. 또한 값이 0 이상이면 스위치에 대한 점프 테이블을 생성하는 것이 더 쉬워집니다.

이것은 Java뿐만 아니라 엄격한 유형 검사 기능을 가진 다른 언어에서도 마찬가지입니다. C, C ++, D, C #이 좋은 예입니다.


4

열거 개인 생성자와 함께, 모든 값은 같은 유형 또는 하위 유형입니다, 내재적으로 최종, 당신이 사용하는 모든 값을 얻을 수 있습니다 values(), 그 취득 name()또는 ordinal()값을하거나 번호 또는 이름으로 열거를 찾아 볼 수 있습니다.

서브 클래스를 정의 할 수도 있습니다 (공식적으로 최종적이지만 다른 방법으로는 할 수없는 일).

enum Runner implements Runnable {
    HI {
       public void run() {
           System.out.println("Hello");
       }
    }, BYE {
       public void run() {
           System.out.println("Sayonara");
       }
       public String toString() {
           return "good-bye";
       }
    }
 }

 class MYRunner extends Runner // won't compile.

4

열거 형 장점 :

  1. 열거 형은 타입 안전하고 정적 필드는 아닙니다
  2. 한정된 수의 값이 있습니다 (존재하지 않는 열거 형 값을 전달할 수 없습니다. 정적 클래스 필드가있는 경우 실수 할 수 있음)
  3. 각 열거 형에는 캡슐화와 같은 여러 속성 (필드 / 게터)이 할당 될 수 있습니다. 간단한 방법 : YEAR.toSeconds () 또는 이와 유사한 방법. 비교 : Colors.RED.getHex ()와 Colors.toHex (Colors.RED)

"예를 들어 열거 형 요소에 특정 값을 쉽게 할당하는 기능"

enum EnumX{
  VAL_1(1),
  VAL_200(200);
  public final int certainValue;
  private X(int certainValue){this.certainValue = certainValue;}
}

"따라서 상당한 노력없이 정수를 열거 형으로 변환하는 기능" int를 열거 형으로 변환하는 방법을 추가하십시오. java java enum 매핑을 포함하는 정적 HashMap <Integer, EnumX>를 추가하십시오 .

ord = VAL_200.ordinal ()을 다시 val_200으로 변환하려면 EnumX.values ​​() [ord]


3

또 다른 중요한 차이점은 Java 컴파일러는 기본 유형의static final 필드 와 문자열 을 리터럴로 취급한다는 것 입니다. 이는 이러한 상수가 인라인이된다는 것을 의미합니다. 전처리 기와 비슷합니다 . 이 SO 질문을 참조하십시오 . 열거 형의 경우에는 해당되지 않습니다.C/C++ #define



2

가장 큰 장점은 열거 형 싱글 톤은 쓰기 쉽고 스레드로부터 안전하다는 것입니다.

public enum EasySingleton{
    INSTANCE;
}

/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
     private volatile DoubleCheckedLockingSingleton INSTANCE;

     private DoubleCheckedLockingSingleton(){}

     public DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

둘 다 비슷하고 구현하여 자체적으로 직렬화를 처리했습니다.

//readResolve to prevent another instance of Singleton
    private Object readResolve(){
        return INSTANCE;
    }


0

후드 컴파일러에서 각 항목에 대한 하위 클래스를 생성하기 때문에 enum할 수 없다고 생각합니다 .finalenum

더 많은 정보 출처


내부적으로 하위 클래스로 분류 될 수 있기 때문에 최종적인 것은 아닙니다. 그러나 아아, 예를 들어 자체 값으로 확장하기 위해 스스로 서브 클래스를 만들 수는 없습니다.
glglgl

0

여기에 게시 된 열거 형의 많은 장점이 있으며 질문에 따라 현재 열거 형을 만들고 있습니다. 그러나 5-6 개의 필드가있는 열거 형이 있습니다.

enum Planet{
EARTH(1000000, 312312321,31232131, "some text", "", 12),
....
other planets
....

이러한 종류의 경우 열거 형에 여러 필드가있는 경우 생성자와 눈알을 볼 때 어떤 값이 어떤 필드에 속하는지 이해하기가 어렵습니다.

클래스 static final상수를Builder 패턴을 사용하여 그러한 객체를 만들면 더 읽기 쉽습니다. 그러나 필요한 경우 열거 형을 사용하면 다른 모든 이점을 잃을 수 있습니다. 이러한 클래스의 한 가지 단점은 Planet개체를 수동으로 추가 해야한다는 것입니다.list/set 입니다.Planets.

나는 여전히 같은 클래스를 통해 열거 형을 선호하는 values()편리하고 당신이 그 (것)들을 사용할 필요가 있다면 당신은 모르실 switch하거나 EnumSet또는 EnumMap미래에 :)


0

주된 이유 : 열거 형은 컴파일 타임에 매개 변수의 의미 적 의미가 명확하고 강력하게 형식화 된 잘 구성된 코드를 작성하는 데 도움이됩니다.

대상물 : Java에서 으로 Enum의 멤버 배열이 최종입니다. 일반적으로 가치 안전 및 테스트에 도움이되므로 유용하지만, 경우에 따라 라이브러리에서 기존 기본 코드를 확장하는 경우와 같은 단점이있을 수 있습니다. 반대로 정적 필드가있는 클래스에 동일한 데이터가있는 경우 런타임에 해당 클래스의 새 인스턴스를 쉽게 추가 할 수 있습니다 (해당 클래스의 Iterable에 추가 할 코드를 작성해야 할 수도 있음). 그러나 Enum의 이러한 동작은 변경 될 수 있습니다. 리플렉션을 사용하면 런타임에 새 멤버를 추가하거나 기존 멤버를 대체 할 수 있지만 대안이없는 특수한 상황에서만 수행해야합니다. 즉, 해키 솔루션이고 예기치 않은 문제가 발생할 수 있습니다. 내 대답을 참조하십시오수 있습니까 추가하고 자바 런타임에 열거의 요소를 제거 .

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