Java枚举和泛型
问题内容:
这件事让我困扰了一阵子。我之前曾问过一些问题,但措辞可能很拙劣,而且例子太抽象了。所以目前尚不清楚我实际上在问什么。我会再尝试。并且请不要下结论。我希望这个问题根本不容易回答!
为什么我不能在Java中使用带有泛型类型参数的枚举?
问题不在于语法上为什么不可能做到这一点。我知道这只是不受支持。问题是:为什么JSR人员会“忘记”或“忽略”这个非常有用的功能?我无法想象与编译器相关的原因,为什么它不可行。
这就是我想做的。这在Java中是可能的。这是Java 1.4创建类型安全枚举的方法:
// A model class for SQL data types and their mapping to Java types
public class DataType<T> implements Serializable, Comparable<DataType<T>> {
private final String name;
private final Class<T> type;
public static final DataType<Integer> INT = new DataType<Integer>("int", Integer.class);
public static final DataType<Integer> INT4 = new DataType<Integer>("int4", Integer.class);
public static final DataType<Integer> INTEGER = new DataType<Integer>("integer", Integer.class);
public static final DataType<Long> BIGINT = new DataType<Long> ("bigint", Long.class);
private DataType(String name, Class<T> type) {
this.name = name;
this.type = type;
}
// Returns T. I find this often very useful!
public T parse(String string) throws Exception {
// [...]
}
// Check this out. Advanced generics:
public T[] parseArray(String string) throws Exception {
// [...]
}
// Even more advanced:
public DataType<T[]> getArrayType() {
// [...]
}
// [ ... more methods ... ]
}
然后,您可以<T>
在其他许多地方使用
public class Utility {
// Generic methods...
public static <T> T doStuff(DataType<T> type) {
// [...]
}
}
但是用枚举是不可能做到的:
// This can't be done
public enum DataType<T> {
// Neither can this...
INT<Integer>("int", Integer.class),
INT4<Integer>("int4", Integer.class),
// [...]
}
现在,正如我所说。我知道这些东西都是按照这种方式设计的。enum
是语法糖。泛型也是如此。实际上,编译器会完成所有工作,并将其转换enums
为的子类,java.lang.Enum
并将泛型转换为强制转换和综合方法。
但是为什么编译器不能走得更远并允许泛型枚举呢?
编辑 :这是我期望作为编译器生成的Java代码:
public class DataType<T> extends Enum<DataType<?>> {
// [...]
}
问题答案:
我会稍作猜测,这是由于Enum类本身的类型参数(定义为)上的协方差问题引起的Enum<E extendsEnum<E>>
,尽管要研究所有极端情况会花费很多。
除此之外,枚举的主要用例是使用诸如EnumSet和valueOf之类的东西,其中您拥有具有不同泛型参数的事物集合,并从字符串获取值,所有这些都不支持或恶化枚举本身的泛型参数。
。
我知道当我尝试使用Generics时,我总是处在痛苦的世界中,而且我想象语言设计师会偷看这个深渊并决定不去那里,特别是因为这些功能是同时开发的,这意味着枚举方面的不确定性更大。
或者换种说法,Class<T>
在处理本身具有通用参数的类时会遇到所有问题,您将不得不进行大量的转换和原始类型的处理。对于您正在查看的用例类型,语言设计师认为并非真正值得的东西。
编辑:响应评论(和汤姆-downvote吗?),嵌套的通用参数使各种不好的事情发生。
枚举实现Comparable。如果泛型在起作用,那么比较客户机代码中枚举的两个任意元素根本行不通。一旦处理了Generic参数的Generic参数,您将面临各种边界问题和头痛。设计一个处理良好的类很困难。在可比的情况下,我无法找到一种方法来使它能够比较枚举的两个任意成员,而又不返回原始类型并得到编译器警告。您可以…吗?
实际上,上述情况令人尴尬地错了,因为我在问题中使用DataType作为思考此问题的模板,但实际上Enum会有一个子类,因此不太正确。
但是,我坚持我的回答的要旨。汤姆(Tom)提出来了EnumSet.complementOf
,当然,我们仍然会valueOf
产生问题,并且就Enum的设计可以起到的作用而言,我们必须意识到那是20/20事后看来的事情。Enum与泛型同时设计,没有验证所有这种极端情况的好处。特别是考虑到具有通用参数的Enum的用例相当有限。(但同样,EnumSet的用例也是如此)。