如果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
。
那:
- 需要使用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
特殊规则,但为什么不尽可能没有完美的类型声明?