developer - java enum 비교




Java enum 리터럴이 generic 형식 매개 변수를 가질 수없는 이유는 무엇입니까? (5)

Becasue "enum"은 열거 형의 약어입니다. 이것은 코드를보다 쉽게 ​​읽을 수 있도록하기 위해 서수 대신에 이름이 붙여진 일련의 상수입니다.

형식화 된 상수의 의도 된 의미가 무엇인지 알 수 없습니다.

Java enums는 훌륭합니다. 제네릭도 마찬가지입니다. 물론 유형 삭제 때문에 후자의 한계를 모두 알고 있습니다. 하지만 이해할 수없는 것이 하나 있습니다. 왜 이렇게 열거 형을 만들 수 없습니까?

public enum MyEnum<T> {
    LITERAL1<String>,
    LITERAL2<Integer>,
    LITERAL3<Object>;
}

이 제네릭 형식 매개 변수 <T> 는 여러 위치에서 유용 할 수 있습니다. 메소드에 제네릭 형식 매개 변수를 상상해보십시오.

public <T> T getValue(MyEnum<T> param);

또는 enum 클래스 자체에서도 :

public T convert(Object o);

더 구체적인 예 # 1

위의 예제가 너무 추상적으로 보일 수도 있으므로 여기에 왜 내가 이것을하고 싶은지에 대한 좀 더 실제적인 예가 있습니다. 이 예제에서는

  • Enums, 왜냐하면 유한 속성 키 집합을 열거 할 수 있기 때문입니다.
  • 제네릭은 속성을 저장하기위한 메서드 수준의 유형 안전성을 가질 수 있기 때문에
public interface MyProperties {
     public <T> void put(MyEnum<T> key, T value);
     public <T> T get(MyEnum<T> key);
}

더 구체적인 예 # 2

데이터 유형 열거 형 :

public interface DataType<T> {}

public enum SQLDataType<T> implements DataType<T> {
    TINYINT<Byte>,
    SMALLINT<Short>,
    INT<Integer>,
    BIGINT<Long>,
    CLOB<String>,
    VARCHAR<String>,
    ...
}

각 열거 형 리터럴은 분명히 제네릭 형식 <T> 기반으로하는 추가 속성을 갖지만 동시에 enum (불변, 단일, 열거 가능 등)

의문:

아무도 이것을 생각하지 않았습니까? 이것은 컴파일러 관련 제한 사항입니까? 사실, 키워드 " enum "이 JVM에 생성 된 코드를 나타내는 구문 설탕으로 구현된다는 점을 고려할 때, 나는이 제한을 이해하지 못합니다.

누가 이걸 설명 할 수 있니? 대답하기 전에 다음을 고려하십시오.

  • 제네릭 형식이 지워진다는 것을 알고 있습니다 :-)
  • Class 객체를 사용하는 해결 방법이 있다는 것을 알고 있습니다. 그것들은 해결 방법입니다.
  • 일반 타입은 컴파일러가 생성 한 타입 캐스트를 적용합니다 (예 : convert () 메소드를 호출 할 때).
  • 제네릭 유형 <T>은 열거 형에 있습니다. 따라서 그것은 각각의 enum의 리터럴에 의해 구속됩니다. 따라서 컴파일러는 String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject); 와 같은 것을 작성할 때 적용 할 형식을 알고 있습니다 String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject); String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
  • T getvalue() 메소드의 제네릭 형식 매개 변수에도 동일하게 적용됩니다. 컴파일러는 String string = someClass.getValue(LITERAL1) 호출 할 때 유형 캐스팅을 적용 할 수 있습니다. String string = someClass.getValue(LITERAL1)

ENUM에는 작동하지 않는 다른 방법이 있습니다. MyEnum.values() 는 무엇을 반환합니까?

MyEnum.valueOf(String name) 어떻습니까?

만약 당신이 컴파일러가 일반적인 메소드를 만들 수 있다고 생각한다면 valueOf를 위해서

공공 정적 MyEnum valueOf (문자열 이름);

MyEnum<String> myStringEnum = MyEnum.value("some string property") 와 같이 호출하기 위해서는 그 중 하나가 작동하지 않습니다. 예를 들어 MyEnum<Int> myIntEnum = MyEnum.<Int>value("some string property") 를 호출하면 어떻게 될까요? 예를 들어 예외를 throw하거나 MyEnum.<Int>value("some double property") 와 같이 호출 할 때 null을 반환하는 등 올바르게 작동하도록 메서드를 구현할 수 없습니다.


대답은 다음과 같습니다.

유형 삭제 때문에

인수 유형이 지워지기 때문에이 두 메소드 중 어느 것도 가능하지 않습니다.

public <T> T getValue(MyEnum<T> param);
public T convert(Object);

그 방법을 실현하려면 다음과 같이 열거 형을 구성 할 수 있습니다.

public enum MyEnum {
    LITERAL1(String.class),
    LITERAL2(Integer.class),
    LITERAL3(Object.class);

    private Class<?> clazz;

    private MyEnum(Class<?> clazz) {
      this.clazz = clazz;
    }

    ...

}

솔직히이 문제는 무엇보다 문제를 찾는 데 더 많은 해결책으로 보인다.

자바 열거 형의 전체 목적은 유사한 String 또는 Integer 표현보다 일관성과 풍부함을 제공하는 방식으로 유사한 속성을 공유하는 유형 인스턴스의 열거를 모델링하는 것입니다.

텍스트 북 열거 형의 예를 들어보십시오. 이는별로 유용하지 않거나 일관성이 없습니다.

public enum Planet<T>{
    Earth<Planet>,
    Venus<String>,
    Mars<Long>
    ...etc.
}

왜 내 다른 행성에 제네릭 유형 변환이 다른 것을 원하나요? 어떤 문제가 해결됩니까? 언어 의미를 복잡하게하는 것이 정당한가? 이 동작이 필요하다면 열거 형을 얻는 것이 가장 좋은 도구일까요?

또한 복잡한 전환을 어떻게 관리합니까?

인스턴스 용

public enum BadIdea<T>{
   INSTANCE1<Long>,
   INSTANCE2<MyComplexClass>;
}

String Integer 를 사용하면 이름이나 서수를 제공하기가 쉽습니다. 그러나 제네릭을 사용하면 모든 유형을 제공 할 수 있습니다. MyComplexClass 로의 변환을 어떻게 관리 하시겠습니까? 이제는 컴파일러에게 일반 열거 형에 제공 할 수있는 유형의 제한된 하위 집합이 있음을 알고 강제로 두 개의 구문을 망가 뜨리고 이미 많은 프로그래머를 피하는 개념 (Generics)에 혼란을 초래합니다.


이것은 현재 JEP-301 Enhanced Enums 에서 논의되고 있습니다. JEP에서 주어진 예제는 정확히 제가 찾고있는 것입니다 :

enum Argument<X> { // declares generic enum
   STRING<String>(String.class), 
   INTEGER<Integer>(Integer.class), ... ;

   Class<X> clazz;

   Argument(Class<X> clazz) { this.clazz = clazz; }

   Class<X> getClazz() { return clazz; }
}

Class<String> cs = Argument.STRING.getClazz(); //uses sharper typing of enum constant

불행히도 JEP는 여전히 중요한 문제로 어려움을 겪고 있습니다. http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html







enums