2009-10-01 84 views
4

冲浪关于Java的源代码,我发现了以下声明:Java的枚举声明是什么意思?

public abstract class Enum<E extends Enum<E>> 

究竟应该如何解释?我被卡住了...

谢谢。

+0

谢谢大家的所有令人印象深刻的输入。我认为每个回答都很有趣(所以我给你+1):) – ATorras 2009-10-02 08:27:59

回答

0

这就像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
+0

OMG!我的想法正在试图解释它。 – ATorras 2009-10-02 08:45:53

+0

“,这又意味着Foo的方法可以安全地将该指针向下转换为其派生子类E.”不对。例如,你可以让'A类延伸Foo '和'B类延伸Foo '。然后在'B'里面,试图将'this'('B'的实例)转换为参数('A')可能会导致类抛出异常。 – newacct 2013-01-04 04:01:37

+0

好吧,你指出了一个病理案例;在您指出的情况下,“B类”不按照预期使用模板。 (即该参数与派生的子类不匹配。) – 2013-01-04 13:46:14

2

你并不孤单。 Ken Arnold不得不this说:

或者,展现在短暂的相同点, 考虑:枚举实际上是定义为ENUM <吨 泛型类 扩展Enum <牛逼> >。你图 出来。我们放弃了试图解释 它。

(从博客条目泛型是有害

+0

谢谢你的链接。我很高兴我不是一个人:) – ATorras 2009-10-02 08:25:02

-1

枚举类需要一个参数化的类型,E,这是枚举的子类。

类型info E用于像compareTo(E o)这样的方法,它需要类声明期间的类型信息(例如Comparable)。

Java编译器会自动传递类型信息,当你创建枚举类,所以你没有看到它时,你声明

enum MyType {...} 

有些事情,我不喜欢怎么通用使用。例如,当接口只需要类信息时,为什么我们需要将类类型传递给接口?我们不能有默认的,或者编译器现在不够聪明?

例如

class String implements Comparable<String> 
1
E

Enum直接(通常混凝土)的子类,与可比使用两个(枚举实现Comparable<E>Comparable<Enum>)和其他一些方法。它会这样做 来访问实际的子类,我怀疑它也需要一些内部实现。

-1

该类不是枚举类型。这只是一个复杂的通用常规课程。很难说(没有看到整个代码)为什么它是这样的设计。但是当我想要一个方法总是返回当前类型的时候,我猜想它可能与自我类型的概念有关。


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(); 
    } 
} 

这又与枚举类型无关。

只是一个思想;

+1

嗯。 “enum”关键字是在幕后使用类Enum <>实现的。 – 2009-10-02 01:06:56

+1

经过一番调查,它似乎是你说的枚举类型的后端。 – NawaMan 2009-10-02 01:15:12

+0

为什么java.lang.Enum的相同构造不能编译?是javac阻止它?为什么如此? – ATorras 2009-10-02 08:30:46

-1

您在代码中创建的所有枚举都将由扩展Enum类的最终类创建。

public enum MyEnum { XYZ } 

将成为

public final class MyEnum extends Enum<MyEnum> 

或者类似的东西(不知道XYZ成为一个实例或类扩展它 - 我也想是不是真的决赛,而编译器会不要让你扩展一个枚举)......无论如何,因为这样的枚举并不真正有用,因为你不能(不应该)真的“自己”做任何事情。

阅读它的javadoc /代码,以更好地理解你可以(不)与你枚举做什么仍然间接有用。

1

使用有界类型的原因>可能由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

+0

Hi @ LES2!谢谢你的回答,但是我不能编译Foo,因为它说“使用“方法不能”静态引用非静态类型E“,这与Bar类相同 – ATorras 2009-10-02 08:40:19

+0

public static > void use(Foo foo){ // use foo } 您必须复制静态方法的通用类型。对不起。 – les2 2009-10-02 14:28:00

+0

“,它是解释在设计通用方法时如何以及何时使用有界通配符的首字母缩写词。”是的,此处没有通配符。 – newacct 2013-01-04 04:02:45