为什么 Java 枚举文字不能具有泛型类型参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4290878/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why shouldn't Java enum literals be able to have generic type parameters?
提问by Lukas Eder
Java enums are great. So are generics. Of course we all know the limitations of the latter because of type erasure. But there is one thing I don't understand, Why can't I create an enum like this:
Java 枚举很棒。泛型也是如此。当然,由于类型擦除,我们都知道后者的局限性。但是有一件事我不明白,为什么我不能创建这样的枚举:
public enum MyEnum<T> {
LITERAL1<String>,
LITERAL2<Integer>,
LITERAL3<Object>;
}
This generic type parameter <T>
in turn could then be useful in various places. Imagine a generic type parameter to a method:
这个泛型类型参数<T>
反过来可能在不同的地方有用。想象一个方法的泛型类型参数:
public <T> T getValue(MyEnum<T> param);
Or even in the enum class itself:
甚至在枚举类本身中:
public T convert(Object o);
More concrete example #1
更具体的例子#1
Since the above example might seem too abstract for some, here's a more real-life example of why I want to do this. In this example I want to use
由于上面的例子对某些人来说可能看起来太抽象了,这里有一个更真实的例子来说明我为什么要这样做。在这个例子中,我想使用
- Enums, because then I can enumerate a finite set of property keys
- Generics, because then I can have method-level type-safety for storing properties
- 枚举,因为这样我就可以枚举一组有限的属性键
- 泛型,因为这样我就可以有方法级的类型安全来存储属性
public interface MyProperties {
public <T> void put(MyEnum<T> key, T value);
public <T> T get(MyEnum<T> key);
}
More concrete example #2
更具体的例子#2
I have an enumeration of data types:
我有一个数据类型的枚举:
public interface DataType<T> {}
public enum SQLDataType<T> implements DataType<T> {
TINYINT<Byte>,
SMALLINT<Short>,
INT<Integer>,
BIGINT<Long>,
CLOB<String>,
VARCHAR<String>,
...
}
Each enum literal would obviously have additional properties based on the generic type <T>
, while at the same time, being an enum (immutable, singleton, enumerable, etc. etc.)
每个枚举文字显然都有基于泛型类型的附加属性<T>
,同时,作为一个枚举(不可变、单例、可枚举等)
Question:
题:
Did no one think of this? Is this a compiler-related limitation? Considering the fact, that the keyword "enum" is implemented as syntactic sugar, representing generated code to the JVM, I don't understand this limitation.
没有人想到这一点吗?这是编译器相关的限制吗?考虑到关键字“ enum”是作为语法糖实现的,代表JVM生成的代码,我不理解这个限制。
Who can explain this to me? Before you answer, consider this:
谁能给我解释一下?在回答之前,请考虑以下问题:
- I know generic types are erased :-)
- I know there are workarounds using Class objects. They're workarounds.
- Generic types result in compiler-generated type casts wherever applicable (e.g. when calling the convert() method
- The generic type <T> would be on the enum. Hence it is bound by each of the enum's literals. Hence the compiler would know, which type to apply when writing something like
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
- The same applies to the generic type parameter in the
T getvalue()
method. The compiler can apply type casting when callingString string = someClass.getValue(LITERAL1)
- 我知道泛型被删除了:-)
- 我知道有使用 Class 对象的解决方法。它们是解决方法。
- 泛型类型会在适用的地方导致编译器生成的类型转换(例如,在调用 convert() 方法时
- 泛型类型 <T> 将在枚举上。因此,它受每个枚举的文字约束。因此编译器会知道,在编写类似的东西时应用哪种类型
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
- 这同样适用于方法中的泛型类型参数
T getvalue()
。编译器可以在调用时应用类型转换String string = someClass.getValue(LITERAL1)
采纳答案by Lukas Eder
This is now being discussed as of JEP-301 Enhanced Enums. The example given in the JEP is, which is precisely what I was looking for:
现在正在讨论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
Unfortunately, the JEP is still struggling with significant issues: http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html
不幸的是,JEP 仍在努力解决重大问题:http: //mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html
回答by capsula
I think because basically Enums can't be instanced
我认为因为基本上 Enums 不能被实例化
Where would you set the T class, if JVM allowed you to do so?
如果 JVM 允许,你会在哪里设置 T 类?
Enumeration is data that is supposed to be always the same, or at least, that it won't change dinamically.
枚举是应该始终相同的数据,或者至少,它不会发生动态变化。
new MyEnum<>()?
新的 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;
}
}
回答by Martin Algesten
The answer is in the question:
答案在问题中:
because of type erasure
因为类型擦除
None of these two methods are possible, since the argument type is erased.
这两种方法都不可能,因为参数类型被删除了。
public <T> T getValue(MyEnum<T> param);
public T convert(Object);
To realise those methods you could however construct your enum as:
要实现这些方法,您可以将枚举构造为:
public enum MyEnum {
LITERAL1(String.class),
LITERAL2(Integer.class),
LITERAL3(Object.class);
private Class<?> clazz;
private MyEnum(Class<?> clazz) {
this.clazz = clazz;
}
...
}
回答by Tom Hawtin - tackline
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.
更新:目前正在添加到JEP 301: Enhanced Enums下的语言中。
回答by Ingo
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.
我不明白类型参数化常量的预期含义是什么。
回答by nsfyn55
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.
java enum 的全部目的是对共享相似属性的类型实例的枚举进行建模,以提供超出可比较的 String 或 Integer 表示形式的一致性和丰富性的方式。
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.
它很容易String
Integer
提供名称或序数。但是泛型允许您提供任何类型。您将如何管理转换为MyComplexClass
?现在,您通过强制编译器知道可以提供给泛型枚举的类型的有限子集并为概念(泛型)引入额外的混淆来混淆两个构造,这似乎已经被很多程序员所忽视。
回答by user1944408
There are other methods in ENUM that wouldn't work. What would MyEnum.values()
return?
ENUM 中还有其他方法不起作用。会MyEnum.values()
返回什么?
What about MyEnum.valueOf(String name)
?
怎么样MyEnum.valueOf(String name)
?
For the valueOf if you think that compiler could make generic method like
对于 valueOf,如果您认为编译器可以生成类似的泛型方法
public static MyEnum valueOf(String name);
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.
为了称之为 like MyEnum<String> myStringEnum = MyEnum.value("some string property")
,那也行不通。例如,如果你打电话MyEnum<Int> myIntEnum = MyEnum.<Int>value("some string property")
怎么办?实现该方法以使其正常工作是不可能的,例如,MyEnum.<Int>value("some double property")
由于类型擦除,在您调用它时抛出异常或返回 null 。