Luk*_*der 13 java generics enums
这件事现在困扰我一段时间了.我以前曾问过问题,但可能是一个错误的措辞和一个过于抽象的例子.所以我不清楚我究竟在问什么.我会再尝试.请不要妄下结论.我希望这个问题根本不容易回答!
为什么我不能在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 ... ]
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以<T>在许多其他地方使用
public class Utility {
// Generic methods...
public static <T> T doStuff(DataType<T> type) {
// [...]
}
}
Run Code Online (Sandbox Code Playgroud)
但这些东西不可能用枚举:
// This can't be done
public enum DataType<T> {
// Neither can this...
INT<Integer>("int", Integer.class),
INT4<Integer>("int4", Integer.class),
// [...]
}
Run Code Online (Sandbox Code Playgroud)
现在,正如我所说.我知道这些东西都是按照这种方式设计的.enum是语法糖.仿制药也是如此.实际上,编译器完成所有工作并将其转换enums为转换子类java.lang.Enum和泛型转换为强制转换和合成方法.
但为什么编译器不能进一步允许通用枚举?
编辑:这是我期望的编译器生成的Java代码:
public class DataType<T> extends Enum<DataType<?>> {
// [...]
}
Run Code Online (Sandbox Code Playgroud)
我会猜测一下,并说这是因为 Enum 类本身的类型参数的协方差问题,它被定义为Enum<E extends Enum<E>>,尽管调查它的所有极端情况有点太多。
除此之外,枚举的主要用例是像 EnumSet 和 valueOf 这样的东西,你有一个具有不同泛型参数的集合,并从字符串中获取值,所有这些都不会支持或更糟枚举本身的泛型参数。
我知道,当我尝试使用泛型时,我总是处于痛苦的世界中,我想象语言设计者看到了那个深渊,并决定不去那里,特别是因为这些功能是同时开发的,这意味着甚至Enum 方面的不确定性更大。
或者换句话说,它会遇到Class<T>处理本身具有泛型参数的类的所有问题,并且您必须进行大量的转换和处理原始类型。语言设计者认为对于您正在查看的用例类型而言,这并不是真正值得的事情。
编辑:为了回应评论(和汤姆 - 否决票?),嵌套通用参数会导致各种不好的事情发生。Enum 实现了 Comparable。如果使用泛型,则根本无法比较客户端代码中枚举的两个任意元素。一旦处理了泛型参数的泛型参数,您最终会遇到各种边界问题和令人头痛的问题。设计一个能够很好地处理它的类是很困难的。在可比较的情况下,我无法找到一种方法来使其可以比较枚举的两个任意成员,而无需恢复为原始类型并获得编译器警告。您可以...吗?
实际上,上面的内容是令人尴尬的错误,因为我使用问题中的 DataType 作为思考这个问题的模板,但实际上 Enum 会有一个子类,所以这不太正确。
不过,我坚持我的回答的要点。汤姆提出了EnumSet.complementOf,当然我们仍然存在valueOf产生问题的问题,并且就 Enum 的设计可能起作用的程度而言,我们必须意识到这是一个 20/20 事后诸葛亮的事情。枚举是与泛型同时设计的,并且没有验证所有此类极端情况的好处。特别是考虑到具有通用参数的 Enum 的用例相当有限。(但话又说回来,EnumSet 的用例也是如此)。