衝浪關於Java的源代碼,我發現了以下聲明:Java的枚舉聲明是什麼意思?
public abstract class Enum<E extends Enum<E>>
究竟應該如何解釋?我被卡住了...
謝謝。
衝浪關於Java的源代碼,我發現了以下聲明:Java的枚舉聲明是什麼意思?
public abstract class Enum<E extends Enum<E>>
究竟應該如何解釋?我被卡住了...
謝謝。
這就像quining! @ LES2在正確的軌道上。
public abstract class Foo <E extends Foo<E>>
{
public static void use(Foo<E> foo) {
// use foo
}
}
如果你有下面的類:
public class FooImpl extends Foo<FooImpl> {
// ...
}
然後,這些遞歸模板讓你的法寶,就是:
Foo
模板要求其參數擴展本身(富)。E
繼而擴展爲Foo<E>
(必須因爲前一點),那麼您已確保Foo
模板對其子類具有「意識」,因爲其子類作爲子類傳遞給它模板參數Foo
的方法可以安全地向this
指針指向其派生的子類E
。OMG!我的想法正在試圖解釋它。 – ATorras 2009-10-02 08:45:53
「,這又意味着Foo的方法可以安全地將該指針向下轉換爲其派生子類E.」不對。例如,你可以讓'A類延伸Foo '和'B類延伸Foo '。然後在'B'裏面,試圖將'this'('B'的實例)轉換爲參數('A')可能會導致類拋出異常。 – newacct 2013-01-04 04:01:37
好吧,你指出了一個病理案例;在您指出的情況下,「B類」不按照預期使用模板。 (即該參數與派生的子類不匹配。) – 2013-01-04 13:46:14
你並不孤單。 Ken Arnold不得不this說:
或者,展現在短暫的相同點, 考慮:枚舉實際上是定義爲ENUM <噸 泛型類 擴展Enum <牛逼> >。你圖 出來。我們放棄了試圖解釋 它。
(從博客條目泛型是有害)
謝謝你的鏈接。我很高興我不是一個人:) – ATorras 2009-10-02 08:25:02
枚舉類需要一個參數化的類型,E,這是枚舉的子類。
類型info E用於像compareTo(E o)這樣的方法,它需要類聲明期間的類型信息(例如Comparable)。
Java編譯器會自動傳遞類型信息,當你創建枚舉類,所以你沒有看到它時,你聲明
enum MyType {...}
有些事情,我不喜歡怎麼通用使用。例如,當接口只需要類信息時,爲什麼我們需要將類類型傳遞給接口?我們不能有默認的,或者編譯器現在不夠聰明?
例如
class String implements Comparable<String>
E
是Enum
直接(通常混凝土)的子類,與可比使用兩個(枚舉實現Comparable<E>
不Comparable<Enum>
)和其他一些方法。它會這樣做 來訪問實際的子類,我懷疑它也需要一些內部實現。
該類不是枚舉類型。這只是一個複雜的通用常規課程。很難說(沒有看到整個代碼)爲什麼它是這樣的設計。但是當我想要一個方法總是返回當前類型的時候,我猜想它可能與自我類型的概念有關。
public abstract class Enum<E extends Enum<E>> {
E getMe() { return (E)this; }
}
public class E1 extends Enum<E1> {
void doE2_only() {}
void doE2() {
// This line is to prove that Javac will see this.getMe() as a function of E1
this.getMe().doE2_only();
}
}
public class E2 extends Enum<E2> {
void doE2_only() {}
void doE2() {
// This line is to prove that Javac will see this.getMe() as a function of E2
this.getMe().doE2_only();
}
}
這又與枚舉類型無關。
只是一個思想;
您在代碼中創建的所有枚舉都將由擴展Enum類的最終類創建。
public enum MyEnum { XYZ }
將成爲
public final class MyEnum extends Enum<MyEnum>
或者類似的東西(不知道XYZ成爲一個實例或類擴展它 - 我也想是不是真的決賽,而編譯器會不要讓你擴展一個枚舉)......無論如何,因爲這樣的枚舉並不真正有用,因爲你不能(不應該)真的「自己」做任何事情。
閱讀它的javadoc /代碼,以更好地理解你可以(不)與你枚舉做什麼仍然間接有用。
使用有界類型的原因>可能由PECS經驗法則解釋(Joshua Bloch在Effective Java中解釋)。
PECS代表「Producer,extends; Consumer super」,它是解釋在設計通用方法時如何以及何時使用有界通配符的首字母縮略詞。
讓我們來看看帶有這個簽名的任何抽象類。
public abstract class Foo <E extends Foo<E>> {
public static void use(Foo<E> foo) {
// use foo
}
}
而且不使用綁定的通配符另一個抽象類:
public abstract class Bar<E> {
public static void use(Bar<E> bar) {
// use bar
}
}
我們的具體類是:
public class FooImpl extends Foo<FooImpl> {
// ...
}
public class AnotherFooImpl extends Foo<AnotherFooImpl> { ... }
public class BarImpl extends Bar<BarImpl> {
///
}
public class AnotherBarImpl extends Bar<AnotherBarImpl> { ... }
我們的主要程序是:
public class FooBar {
public static void main(String[] args) {
Foo.use(new FooImpl()); // works
Foo.use(new AnotherFooImpl()); // works
Bar.use(new BarImpl()); // doesn't work -- why?
Bar.use(new AnotherBarImpl()); // doesn't work -- why?
}
}
使Bar.use(新的BarImp l())工作時,必須使用通配符。
(我認爲 - 從我的頭頂 - 我還沒有編制,所以我希望我是正確的:)
每個枚舉元素是真正的枚舉類型的子類:
enum Foo {
FooImpl, AnotherFooImpl, ...;
}
基類Enum類中有一些方法需要確保它們具有正確類型的子類,爲了正常工作,該語法是必需的。
我希望這有助於(如果你有時間,試試這個例子)。
- LES
謝謝大家的所有令人印象深刻的輸入。我認爲每個回答都很有趣(所以我給你+1):) – ATorras 2009-10-02 08:27:59