【发布时间】:2010-11-27 09:12:04
【问题描述】:
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() 方法时
- 泛型类型
将位于枚举中。因此,它受每个枚举字面量的约束。因此编译器会知道,在编写 String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);之类的内容时应用哪种类型 - 这同样适用于
T getvalue()方法中的泛型类型参数。编译器可以在调用String string = someClass.getValue(LITERAL1)时应用类型转换
【问题讨论】:
-
我也不明白这个限制。我最近遇到了这个问题,其中我的枚举包含不同的“Comparable”类型,并且使用泛型,只有相同类型的 Comparable 类型可以在没有需要抑制的警告的情况下进行比较(即使在运行时会比较正确的类型)。我本可以通过使用枚举中绑定的类型来指定支持哪种可比较类型来消除这些警告,但是我不得不添加 SuppressWarnings 注释 - 没有办法!由于 compareTo 确实抛出了一个类转换异常,我猜这没关系,但仍然......
-
(+1) 我正试图缩小项目中的类型安全漏洞,但被这个任意限制阻止了。考虑一下:将
enum变成我们在Java 1.5 之前使用的“类型安全枚举”习语。突然,您可以将枚举成员参数化。这可能就是我现在要做的。 -
@EdwinDalorzo:用来自jOOQ 的具体示例更新了问题,这在过去非常有用。
-
@LukasEder 我现在明白你的意思了。看起来很酷的一个新功能。也许你应该在project coin mailing list 中提出建议
-
完全同意。没有泛型的枚举被削弱了。你的案例#1也是我的。如果我需要通用枚举,我会放弃 JDK5 并以普通的旧 Java 1.4 风格实现它。这种方法还有额外的好处:我不必将所有常量都放在一个类甚至包中。因此,按功能打包的样式要好得多。这对于类似配置的“枚举”来说是完美的——常量根据它们的逻辑含义分布在包中(如果我希望看到它们,我会显示类型层次结构)。