Hi all,
Surfing on the source code of Java, I found the following declaration:
public abstract class Enum<E extends Enum<E>>
How should it be interpreted? I'm stuck with it...
Thank you.
Hi all,
Surfing on the source code of Java, I found the following declaration:
public abstract class Enum<E extends Enum<E>>
How should it be interpreted? I'm stuck with it...
Thank you.
You're not alone. Ken Arnold had this to say:
Or, to show the same point in brief, consider this: Enum is actually a generic class defined as Enum<T extends Enum<T>>. You figure it out. We gave up trying to explain it.
(from the blog entry Generics Considered Harmful)
Enum class requires a parameterized type, E, which is the subclass of Enum.
The type info, E, is needed for methods like compareTo(E o), which requires type info during class declaration (e.g. Comparable).
Java compiler automatically pass in type info when you create enum class, so you don't see it when you declare
enum MyType {...}
There are things that I don't like how generic is used. For example, why do we need to verbosely pass the class type to the interface when the interface only requires the class info? we can't have a default, or compiler is not smart enough nowadays?
e.g.
class String implements Comparable<String>
E is the direct (usually concrete) subclass of Enum, used both with Comparable (Enum implements Comparable not Comparable) and a few other methods. It does this to access the actual subclass, which I suspect it needs for some of the internal implementation as well.
This class is not an enumerator type. It is just a complex generic regular class. It is hard to tell (without see the whole code) why it is design like this. But I'll guess it may have anything to do with the concept of self type when you want to have a method returning the current type always.
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();
}
}
Which again, has nothing to do with enumerator types.
Just a thougth;
All the enum you create in your code will be created by a final class extending the Enum class.
public enum MyEnum { XYZ }
will become
public final class MyEnum extends Enum<MyEnum>
Or something like that (not sure if XYZ become an instance or a class extending it - also I think it is not really final, but rather the compiler will not let you extend an enum) ... Anyway, as such Enum is not really useful, because you cannot (should not) really "do" anything with it yourself.
It is still indirectly useful to read its javadoc/code to better understand what you can(not) do with you enum.
The reason to use the bounded type > is probably explained by the PECS rule of thumb (explained in Effective Java by Joshua Bloch).
PECS stands for "Producer, extends; Consumer super", and it is an acronym that explains how and when to use bounded wildcards when designing generic methods.
Let's examine any abstract class with this signature.
public abstract class Foo <E extends Foo<E>> {
public static void use(Foo<E> foo) {
// use foo
}
}
And another abstract class that doesn't use the bounded wildcard:
public abstract class Bar<E> {
public static void use(Bar<E> bar) {
// use bar
}
}
Our concrete classes are:
public class FooImpl extends Foo<FooImpl> {
// ...
}
public class AnotherFooImpl extends Foo<AnotherFooImpl> { ... }
public class BarImpl extends Bar<BarImpl> {
///
}
public class AnotherBarImpl extends Bar<AnotherBarImpl> { ... }
Our main program is:
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?
}
}
To make Bar.use(new BarImpl()) work, the wildcard must be used.
(I think - off the top of my head - I haven't compiled it, so I hope I'm right :)
Each enum element is really a subclass of the enum type:
enum Foo {
FooImpl, AnotherFooImpl, ...;
}
There are some methods in the base Enum class that need to make sure they have an subclass of the correct type, and for that to work, that syntax is necessary.
I hope this helps (try the example if you have the time).
-- LES
It's like quining! @LES2 is on the right track.
public abstract class Foo <E extends Foo<E>>
{
public static void use(Foo<E> foo) {
// use foo
}
}
If you have the following class:
public class FooImpl extends Foo<FooImpl> {
// ...
}
then the magic that these recursive templates gives you, is that:
Foo
template requires that its parameter extends itself (Foo).E
, in turn, extends Foo<E>
(it has to because of the previous point) then you have ensured that the Foo
template has an "awareness" of its subclass, since its subclass is passed into it as a template parameterFoo
's methods can safely downcast the this
pointer to its derived subclass E
.