为什么不应该';Java枚举文本是否能够具有泛型类型参数?
Java枚举非常好。泛型也是如此。当然,由于类型擦除,我们都知道后者的局限性。但有一件事我不明白,为什么我不能创建这样的枚举:为什么不应该';Java枚举文本是否能够具有泛型类型参数?,java,generics,enums,Java,Generics,Enums,Java枚举非常好。泛型也是如此。当然,由于类型擦除,我们都知道后者的局限性。但有一件事我不明白,为什么我不能创建这样的枚举: public enum MyEnum<T> { LITERAL1<String>, LITERAL2<Integer>, LITERAL3<Object>; } 更具体的例子#1 因为上面的例子对某些人来说可能太抽象了,这里有一个更真实的例子来说明我为什么要这么做。在这个例子中,我想使用 枚举,
public enum MyEnum<T> {
LITERAL1<String>,
LITERAL2<Integer>,
LITERAL3<Object>;
}
更具体的例子#1
因为上面的例子对某些人来说可能太抽象了,这里有一个更真实的例子来说明我为什么要这么做。在这个例子中,我想使用
- 枚举,因为这样我可以枚举一组有限的属性键
- 泛型,因为这样我就可以有方法级别的类型安全性来存储属性
公共接口MyProperties{
公共作废put(MyEnum键,T值);
公共T-get(MyEnum密钥);
}
更具体的例子#2
我有一个数据类型的枚举:
public interface DataType<T> {}
public enum SQLDataType<T> implements DataType<T> {
TINYINT<Byte>,
SMALLINT<Short>,
INT<Integer>,
BIGINT<Long>,
CLOB<String>,
VARCHAR<String>,
...
}
公共接口数据类型{}
公共枚举SQLDataType实现数据类型{
TINYINT,
斯莫林,
INT,
比金特,
克洛布,
瓦查尔,
...
}
每个枚举文字显然都有基于泛型类型的附加属性,同时也是一个枚举(不可变、单例、可枚举等)
问题:
没人想到这个吗?这是与编译器相关的限制吗?考虑到关键字“enum”是作为语法糖实现的,代表JVM生成的代码,我不理解这个限制 谁能给我解释一下?在回答之前,考虑一下:
- 我知道泛型类型被删除:-)
- 我知道有一些使用类对象的变通方法。它们是变通办法
- 泛型类型在适用的情况下会导致编译器生成类型强制转换(例如,在调用convert()方法时)
- 泛型类型将位于枚举上。因此它由每个枚举的文本绑定。因此编译器将知道在编写类似
String String=LITERAL1.convert(myObject);Integer Integer=LITERAL2.convert(myObject);
- 这同样适用于
方法中的泛型类型参数。编译器可以在调用T getvalue()
String String=someClass.getvalue(LITERAL1)
- 我认为,因为基本上枚举不能实例化
如果JVM允许,您将在哪里设置T类
枚举是指数据应该总是相同的,或者至少不会发生变化
新的MyEnum()
不过,以下方法可能有用
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;
}
}
问题的答案是: 因为类型擦除 这两种方法都不可能,因为参数类型已被擦除
public <T> T getValue(MyEnum<T> param);
public T convert(Object);
publictgetvalue(MyEnum参数);
公共T转换(对象);
为了实现这些方法,您可以将枚举构造为:
public enum MyEnum {
LITERAL1(String.class),
LITERAL2(Integer.class),
LITERAL3(Object.class);
private Class<?> clazz;
private MyEnum(Class<?> clazz) {
this.clazz = clazz;
}
...
}
公共枚举MyEnum{
LITERAL1(String.class),
LITERAL2(Integer.class),
LITERAL3(Object.class);
私人课堂;
私有MyEnum(类clazz){
this.clazz=clazz;
}
...
}
因为你不能。说真的。这可以添加到语言规范中。但事实并非如此。这会增加一些复杂性。成本效益意味着它不是一个高优先级
更新:当前添加到语言中。因为“enum”是枚举的缩写。
它只是一组命名常量,用来代替序数,使代码更具可读性
我不明白类型参数化常量的预期含义是什么。坦率地说,这似乎更像是一种寻找问题的解决方案 java枚举的全部目的是对共享相似属性的类型实例的枚举进行建模,其提供的一致性和丰富性超出了可比较的字符串或整数表示 以教科书枚举为例。这不是非常有用或一致:
public enum Planet<T>{
Earth<Planet>,
Venus<String>,
Mars<Long>
...etc.
}
公共枚举行星{
地球,,
维纳斯
火星
等
}
为什么我希望我的不同星球有不同的泛型类型转换?它解决了什么问题?它是否证明了使语言语义复杂化的合理性?如果我确实需要这种行为,枚举是实现它的最佳工具吗
此外,您将如何管理复杂的转换
比如说
public enum BadIdea<T>{
INSTANCE1<Long>,
INSTANCE2<MyComplexClass>;
}
public enum baddea{
实例1,
实例2;
}
使用
String
Integer
来提供名称或序号很容易。但是泛型允许您提供任何类型。您如何管理到MyComplexClass
的转换?现在,通过强制编译器知道可以提供给gene的类型的有限子集,您可以将两个结构弄糟ric枚举并对概念(泛型)引入额外的混淆,这似乎是许多程序员都无法理解的。枚举中还有其他方法不起作用。MyEnum.values()
会返回什么
那MyEnum.valueOf(字符串名)呢
如果您认为编译器可以使泛型方法
公共静态MyEnum valueOf(字符串名称)
为了像调用MyEnum myStringEnum=MyEnum.value(“某些字符串属性”)那样调用它,这也不起作用。
例如,如果您调用MyEnum myIntEnum=MyEnum.value(“某些字符串属性”)
,该怎么办?
不可能实现该方法来正确工作,例如,当您像
MyEnum.value(“某个双属性”)那样调用它时,抛出异常或返回null
因为类型擦除。很遗憾,这一点已于讨论,但被撤回。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
enum参数{//声明泛型枚举
字符串(STRING.class),
整数(INTEGER.class);
课堂讨论;
参数(类clazz){this.clazz=clazz;}
类getClazz(){
public enum Planet<T>{
Earth<Planet>,
Venus<String>,
Mars<Long>
...etc.
}
public enum BadIdea<T>{
INSTANCE1<Long>,
INSTANCE2<MyComplexClass>;
}
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