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

时间:2010-06-18 07:36:32

标签: java generics enums

请看 Java Enum definitionWhy in java enum is declared as Enum<E extends Enum<E>> 一般性的讨论。如果Enum类被定义为

,我想知道究竟会破坏什么(不再是类型安全,或者需要额外的强制转换等)
public class Enum<E extends Enum> 

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

interface MyComparable<T> {
    int myCompare(T o);
}

class MyEnum<E extends MyEnum> implements MyComparable<E> {
    public int myCompare(E o) { return -1; }
}

class FirstEnum extends MyEnum<FirstEnum> {}

class SecondEnum extends MyEnum<SecondEnum> {}

有了它,我无法在这种情况下找到任何好处。

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

class ThirdEnum extends MyEnum<SecondEnum> {}

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

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

5 个答案:

答案 0 :(得分:2)

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

public class Enum<E extends Enum<?>>

同样的效果。

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

class FirstEnum extends MyEnum<SecondEnum> {
}

class SecondEnum extends MyEnum<FirstEnum> {
}

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

答案 1 :(得分:1)

考虑Enum<E>.compareTo(E other)

这:

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

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

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

答案 2 :(得分:1)

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

考虑到递归部分可以做到这一点:

class MyEnum<E extends MyEnum<E>> {
    private Thing<E> util1() { return someObject }
    private void util2(E e) {}
    public int method(E o) { 
        Thing<E> 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类中,并且这些调用将是类型安全的。

答案 3 :(得分:0)

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

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

public abstract class MyEnum implements Comparable<MyEnum>
{
    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枚举,两个相等的测试都会产生相同的结果。

答案 4 :(得分:0)

`X extends Enum<Y>`

是非法的。那个相关者。编译器可以有enum的特殊规则,但如果可能的话,为什么没有完美的类型声明?