2010-06-18 58 views
12

请参阅 Java Enum definitionWhy in java enum is declared as Enum<E extends Enum<E>> 一般性讨论。在这里,我想了解究竟是什么将被打破(不是类型安全的了,或者需要额外的管型等),如果枚举类是测试我的想法定义为什么是Java中不同,如果枚举声明没有递归部分

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与递归定义的事实是
一)不相关的,因为真正的枚举你不能这样做,只是因为你不能延长枚举你自己
b)不正确 - 请在编译器中试试看,它实际上能够编译没有任何错误

PPS。我越来越倾向于相信,这里的正确答案是“如果你删除递归部分,什么都不会改变” - 但我无法相信这一点。

回答

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元素上调用类型安全的方法,并且这些调用会类型安全。

+1

只是一个小纸条,'o.util2(this)'不会被编译,因为这被认为是MyEnum 而不是E.你可以添加第二个参数'E o1'并调用'o.util2(o1)'尽管相同效果:它会用'E extends MyEnum '编译,但不能用'E extends MyEnum ' – 2010-06-18 08:54:21

+0

'谢谢,我刚纠正了那个错误。 – 2010-06-18 09:00:26

+0

谢谢!如果删除递归,那么该代码确实被标记为不安全!你知道jdk中该功能的真实用法吗? – atamur 2010-06-18 10:30:32

1

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

即:

  • 需求为E而不是枚举工作,让你不要试图一个枚举值与值从不同的枚举
  • 需求比较能够得到序枚举的值,通过ordinal()方法Enum上声明。

您会如何提出在没有当前约束的情况下进行工作?

这只是我想出的第一个......我相信还有很多其他人。基本上这是一种说法,“你不应该试图把所有的枚举看作等价的 ......枚举本身是一个封闭的集合,但是所有的枚举都具有某些属性。”

+0

compareTo - 看到我的qn。就像你说的那样,它就是这样工作的。没有任何递归。没有看到序号问题 - 你能否提供一些破解/不是类型安全的代码? – atamur 2010-06-18 08:13:57

+0

@atamur:我没有注意到你的例子中的原始类型位(你在问的前五分钟内编辑过吗?也许我只是误读了它)。事实上,你需要一个原始类型立即让我紧张,说实话... – 2010-06-18 10:35:26

+0

如果序号是原因,那么'类枚举>'就足够了。 – newacct 2015-02-25 06:18:54

2

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

public class Enum<E extends Enum<?>> 

达到相同的效果。

而且,这种类型的通用的,你可以这样做:

class FirstEnum extends MyEnum<SecondEnum> { 
} 

class SecondEnum extends MyEnum<FirstEnum> { 
} 

这对我来说似乎是它可以导致很多的麻烦。更确切地说,您无法将FirstEnum类型的枚举与相同类型的枚举进行比较,您必须将其与其他类型的枚举进行比较,如果您要排序的List<FirstEnum>确实很麻烦。如果我设置E而不是?,此示例不会编译,因为SecondEnum的类型不是E extends MyEnum<E>(这会导致循环继承)。它会工作,如果FirstEnum extends MyEnum<FirstEnum>尽管(这将意味着SecondEnum是FirstEnum的子类 - 正常的分层继承)。

+0

原始类型听起来很有趣 - 但如果实际尝试,javac不会发出任何原始警告。 请参阅qn中的我的ps。有两点为什么这是不相关的。 – atamur 2010-06-18 08:17:05

+1

我使用的是日食,它给出了关于原始类型的警告(更不用说太阳已经说过我们不应该再使用原始类型了)。也许javac需要某种激活的选项来抱怨这个? – 2010-06-18 08:35:49

+1

另外,ps的第二点对于我的例子来说不是真的,如果我将该类设置为'public class MyEnum >'它不会编译。至于第一点,我认为它可能能够生成.class文件,以便它具有类似这样写的类的方法签名(通过使用非标准编译器),即使javac不会让你编译' public Enum FirstEnum扩展MyEnum '或类似的东西。 – 2010-06-18 08:41:23

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枚举,两个相等的测试都会产生相同的结果。

+0

恐怕你不明白我的qn。如果你看我的代码 - MyEnum使用泛型,而不是递归位。 – atamur 2010-06-18 10:14:49

0
`X extends Enum<Y>` 

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