2010-06-18 64 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的特殊規則,但如果可能的話,爲什麼不能有一個完美的類型聲明?