为什么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
因为上面的例子对某些人来说可能太抽象了,这里有一个更真实的例子来说明我为什么要这么做。在这个例子中,我想使用
- 枚举,因为这样我可以枚举一组有限的属性键
- 泛型,因为这样我就可以有方法级别的类型安全性来存储属性
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”是作为语法糖实现的,代表JVM生成的代码,我不理解这个限制
谁能给我解释一下?在回答之前,考虑一下:
- 我知道泛型类型被删除:-)
- 我知道有一些使用类对象的变通方法。它们是变通办法李>
- 泛型类型在适用的情况下会导致编译器生成类型强制转换(例如,在调用convert()方法时)
- 泛型<;T>;将在枚举中。因此,它由每个枚举的文本绑定。因此,编译器将知道在编写类似
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
的内容时应用哪种类型 - 这同样适用于
T getvalue()
方法中的泛型类型参数。编译器可以在调用String string = someClass.getValue(LITERAL1)
时应用类型转换
# 1 楼答案
令人遗憾的是,这一点在JEP-301 Enhanced Enums时已经讨论过,后来被撤回。JEP中给出的示例正是我想要的:
不幸的是,正义与平等党正在与重大问题斗争,这些问题无法解决:http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html
# 2 楼答案
因为你不能,说真的。这可以添加到语言规范中,但还没有。这会增加一些复杂性。这种成本效益比意味着它不是一个优先考虑的问题
更新:当前正在添加到JEP 301: Enhanced Enums下的语言中
# 3 楼答案
问题的答案是:
这两种方法都不可能,因为参数类型已被擦除
为了实现这些方法,您可以将枚举构造为:
# 4 楼答案
枚举中还有其他方法不起作用。
MyEnum.values()
会返回什么那
MyEnum.valueOf(String name)
呢如果您认为编译器可以使泛型方法
为了像
MyEnum<String> myStringEnum = MyEnum.value("some string property")
那样称呼它,这也行不通。 例如,如果调用MyEnum<Int> myIntEnum = MyEnum.<Int>value("some string property")
,会怎么样? 不可能实现该方法来正确工作,例如,由于类型擦除,当您像MyEnum.<Int>value("some double property")
一样调用它时,抛出异常或返回null# 5 楼答案
通过使用这个Java注释处理器https://github.com/cmoine/generic-enums,您可以编写如下内容(convert方法作为示例实现):
注释处理器将生成一个枚举
MyEnumExt
(可自定义),它克服了java枚举的限制。相反,它生成了一个完全可用作枚举的Java类(最后,一个枚举被编译成一个实现Enum
的Java类)# 6 楼答案
坦率地说,这似乎更像是寻找问题的解决方案,而不是任何东西
java枚举的全部目的是对共享相似属性的类型实例的枚举进行建模,其提供的一致性和丰富性超出了可比较的字符串或整数表示
以教科书枚举为例。这不是非常有用或一致:
为什么我希望我的不同行星有不同的泛型类型转换?它解决了什么问题?这是否证明了语言语义的复杂性?如果我真的需要这个行为,枚举是实现它的最好工具吗
此外,您将如何管理复杂的转换
比如说
用}很容易提供名称或序号。但是泛型可以让你提供任何类型。您将如何管理到
String
{MyComplexClass
的转换?现在,通过强制编译器知道可以提供给泛型枚举的类型的有限子集,并对概念(泛型)引入额外的混淆(泛型),这似乎已经让许多程序员无法理解,从而破坏了两个构造