Java 열거 리터럴이 일반 유형 매개 변수를 가질 수없는 이유는 무엇입니까?
Java 열거 형은 훌륭합니다. 제네릭도 마찬가지입니다. 물론 우리는 유형 삭제로 인해 후자의 한계를 알고 있습니다. 그러나 이해할 수없는 한 가지가 있습니다. 왜 이런 식으로 열거 형을 만들 수 없습니까?
public enum MyEnum<T> {
LITERAL1<String>,
LITERAL2<Integer>,
LITERAL3<Object>;
}
이 제네릭 형식 매개 변수 <T>
는 여러 곳에서 유용 할 수 있습니다. 메소드에 일반 유형 매개 변수를 상상해보십시오.
public <T> T getValue(MyEnum<T> param);
또는 열거 형 클래스 자체에서도 :
public T convert(Object o);
보다 구체적인 예 # 1
위의 예는 일부에서는 너무 추상적으로 보일 수 있으므로 여기에 내가 원하는 이유에 대한 더 실제적인 예가 있습니다. 이 예에서는 사용하고 싶습니다
- 열거 형, 유한 속성 키 집합을 열거 할 수 있기 때문에
- 제네릭 (Generics) : 속성을 저장하기위한 메서드 수준 형식 안전성을 가질 수 있기 때문에
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>,
...
}
각 열거 형 리터럴은 generic 형식을 기반으로 추가 속성 <T>
을 갖는 동시에 열거 형 (불변, 단일 톤, 열거 가능 등)입니다.
질문:
아무도 이것을 생각하지 않았습니까? 이것이 컴파일러 관련 제한입니까? 사실 키워드 " enum "이 JVM에 생성 된 코드를 나타내는 구문 설탕으로 구현 된다는 점을 고려하면 이 제한을 이해하지 못합니다.
누가 나에게 설명 할 수 있습니까? 대답하기 전에 다음을 고려하십시오.
- 일반 유형이 지워지는 것을 알고 있습니다 :-)
- Class 객체를 사용하는 해결 방법이 있다는 것을 알고 있습니다. 그들은 해결 방법입니다.
- 제네릭 형식은 해당되는 경우 (예 : convert () 메서드 호출시) 컴파일러 생성 형식 캐스트를 생성합니다.
- 제네릭 형식 <T>는 열거 형에 있습니다. 따라서 열거 형의 각 리터럴에 바인딩됩니다. 따라서 컴파일러는 다음과 같은 내용을 작성할 때 적용 할 유형을 알고 있습니다.
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
T getvalue()
메소드 의 일반 유형 매개 변수에도 동일하게 적용됩니다 . 컴파일러는 호출 할 때 타입 캐스팅을 적용 할 수 있습니다String string = someClass.getValue(LITERAL1)
이것은 현재 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
대답은 질문에 있습니다.
유형 삭제 때문에
인수 유형이 지워 지므로이 두 가지 방법 중 어느 것도 사용할 수 없습니다.
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;
}
...
}
Because you can't. Seriously. That could be added to the language spec. It hasn't been. It would add some complexity. That benefit to cost means it isn't a high priority.
Update: Currently being added to the language under JEP 301: Enhanced Enums.
There are other methods in ENUM that wouldn't work. What would MyEnum.values()
return?
What about MyEnum.valueOf(String name)
?
For the valueOf if you think that compiler could make generic method like
public static MyEnum valueOf(String name);
in order to call it like MyEnum<String> myStringEnum = MyEnum.value("some string property")
, that wouldn't work either. For example what if you call MyEnum<Int> myIntEnum = MyEnum.<Int>value("some string property")
? It is not possible to implement that method to work correctly, for example to throw exception or return null when you call it like MyEnum.<Int>value("some double property")
because of type erasure.
Frankly this seems like more of a solution in search of a problem than anything.
The entire purpose of the java enum is to model a enumeration of type instances that share similiar properties in a way that provides consistency and richness beyond that of comparable String or Integer representations.
Take an example of a text book enum. This is not very useful or consistent:
public enum Planet<T>{
Earth<Planet>,
Venus<String>,
Mars<Long>
...etc.
}
Why would I want my different planets to have different generic type conversions? What problem does it solve? Does it justify complicating the language semantics? If I do need this behavior is an enum the best tool to achieve it?
Additionally how would you manage complex conversions?
for Instance
public enum BadIdea<T>{
INSTANCE1<Long>,
INSTANCE2<MyComplexClass>;
}
Its easy enough with String
Integer
to supply the name or ordinal. But generics would allow you to supply any type. How would you manage the conversion to MyComplexClass
? Now your mucking up two constructs by forcing the compiler to know that there are a limited subset of types that can be supplied to generic enums and introducing additional confusion to concept(Generics) that already seems elude a lot of programmers.
Becasue "enum" is the abbreviation for enumeration. It's just a set of named constants that stand in place of ordinal numbers to make the code better readable.
I don't see what the intended meaning of a type-parameterized constant could be.
I think because basically Enums can't be instanced
Where would you set the T class, if JVM allowed you to do so?
Enumeration is data that is supposed to be always the same, or at least, that it won't change dinamically.
new MyEnum<>()?
Still the following approach may be useful
public enum MyEnum{
LITERAL1("s"),
LITERAL2("a"),
LITERAL3(2);
private Object o;
private MyEnum(Object o) {
this.o = o;
}
public Object getO() {
return o;
}
public void setO(Object o) {
this.o = o;
}
}
'development' 카테고리의 다른 글
std :: vector :: erase () 및 std :: deque :: erase ()의 할당 복사 / 이동 (0) | 2020.06.26 |
---|---|
Java 클래스 파일 형식 주요 버전 번호 목록? (0) | 2020.06.26 |
Javascript에서 예외를 다시 발생 시키지만 스택을 보존하려면 어떻게해야합니까? (0) | 2020.06.26 |
장고 메모리 사용량 감소. (0) | 2020.06.26 |
브라우저에서 JavaScript를 샌드 박스로 실행할 수 있습니까? (0) | 2020.06.26 |