如果Enum声明没有递归部分,Java会有什么不同

请参阅Java Enum定义和为什么在java enum中声明为Enum <E extends Enum >进行一般性讨论。 如果Enum类被定义为,我想知道究竟会破坏什么(不再是类型安全,或者需要额外的强制转换等)

public class Enum 

我正在使用此代码来测试我的想法:

 interface MyComparable { int myCompare(T o); } class MyEnum implements MyComparable { public int myCompare(E o) { return -1; } } class FirstEnum extends MyEnum {} class SecondEnum extends MyEnum {} 

有了它,我无法在这个确切的情况下找到任何好处。

PS。 我不被允许这样做的事实

 class ThirdEnum extends MyEnum {} 

当MyEnum用递归定义时
a)不相关,因为有了真正的枚举,你不能仅仅因为你不能自己扩展枚举而这样做
b)不正确 – 请在编译器中尝试它并看到它实际上能够编译没有任何错误

PPS。 我越来越倾向于认为这里的正确答案是“如果删除递归部分,没有任何改变” – 但我简直无法相信。

我相信这样做的一个令人信服的理由是它使MyEnum类中的代码更加类型安全。

考虑到递归部分使这样的事情成为可能:

 class MyEnum> { private Thing util1() { return someObject } private void util2(E e) {} public int method(E o) { Thing thingy = o.util1(); // You can call the util1 method on o and get a type safe return element. E o1 = // I don't care how you get a parametrized E object. o.util2(o1); // You can call the util2 method with a typesafe parameter. } } 

简而言之,该递归允许您将类型安全方法放在可以在任何E元素上调用的Enum类中,并且这些调用将是类型安全的。

好吧,首先它会抱怨使用原始类型,但你可以这样做:

 public class Enum> 

为了同样的效果。

此外,使用这种类型的通用,您可以执行以下操作:

 class FirstEnum extends MyEnum { } class SecondEnum extends MyEnum { } 

这对我来说似乎可能会导致很多麻烦。 更确切地说,你不能将FirstEnum类型的枚举与同一类型的枚举进行比较,你必须将它与另一种类型的枚举进行比较,如果你有一个你想要排序的List ,那真的很麻烦。 如果我将E设置为o,则该示例将无法编译? 因为SecondEnum不属于E extends MyEnum (这将导致循环inheritance)。 如果FirstEnum extends MyEnum ,它将起作用(这意味着SecondEnum是FirstEnum的子类 – 正常的层次inheritance)。

考虑Enum.compareTo(E other)

那:

  • 需要使用E而不是枚举,这样您就不会尝试将一个枚举值与来自不同枚举的值进行比较
  • 需要能够通过Enum声明ordinal()方法获取枚举的序数值。

如果没有当前的约束,你会如何提出这项工作?

这只是我提出的第一个……我相信还有很多其他人。 基本上它是一种说法,“你不应该试图将所有的枚举视为彼此等同……枚举本身就是一个封闭的集合,但所有的枚举都具有某些属性。”

如果您没有generics类型参数,那么您将无法为您创建的枚举的特定子类型扩展Comparable

您可以忽略这一点,并创建自己的MyEnum类型,其行为大致相同,但没有不同的MyEnum无法比较的限制:

 public abstract class MyEnum implements Comparable { private final int ordinal; protected MyEnum ( int ordinal ) { this.ordinal = ordinal; } public int ordinal () { return ordinal ; } public int compareTo ( MyEnum other ) { return ordinal - other.ordinal; // ignore overflow for now } public boolean equals (Object other) { return ordinal == ((MyEnum)other).ordinal; } public int hashCode () { return ordinal; } } 

这与枚举对于定义的操作的行为大致相同,但不是通用类型安全实现服从LSP – 如果MyEnum的不同子类具有相同的序数值,则它们彼此相当或相等。

 public static class EnumA extends MyEnum { private EnumA ( int ordinal ) { super ( ordinal ); } public static final EnumA a = new EnumA ( 0 ); public static final EnumA b = new EnumA ( 1 ); } public static class EnumB extends MyEnum { private EnumB ( int ordinal ) { super ( ordinal ); } public static final EnumB x = new EnumB ( 0 ); public static final EnumB y = new EnumB ( 1 ); } public static void main ( String...args ) { System.out.println ( EnumA.a.compareTo ( EnumB.x ) ); System.out.println ( EnumA.a.equals ( EnumB.x ) ); System.out.println ( EnumA.a.compareTo ( EnumB.y ) ); System.out.println ( EnumA.a.equals ( EnumB.y ) ); } 

在这种情况下,如果不重写equals ,则会失去x.comparesTo(y)=0意味着x.equals(y)的约定。 如果你重写equals,那么有些情况下x.equals(y)并不意味着x == y (和其他值对象一样),而对于Java枚举,两个相等的测试产生相同的结果。

 `X extends Enum` 

会是非法的。 这相关的。 编译器可以有enum特殊规则,但为什么不尽可能没有完美的类型声明?