values() of an Enumeration type that is a generic parameter?

E

Eric Smith

I'm trying to write a generic class using an enumeration as a type
parameter, but I ran into trouble trying to iterate over the enumeration
values:

class Foo<E extends Enum<E>>
{
public void doSomething ()
{
for (E index: E.values ())
{
// do stuff here
}
}
}

The compiler says:

Foo.java:55: cannot find symbol
symbol : method values()
location: class java.lang.Enum<E>
for (E index: E.values ())
^
1 error

Does E not inherit the values() method of the enumeration type?
Is there some other way I can do this?

I'm also rather unclear on why various JDK classes use
<E extends Enum<E>> for their parameter; I can't quite seem to
grasp what it means. I tried just using <E extends Enum>, but the
compiler had the same complaint.

Any hints will be much appreciated!

Thanks!
Eric
 
T

Tom Hawtin

Eric said:
Foo.java:55: cannot find symbol
symbol : method values()
location: class java.lang.Enum<E>
for (E index: E.values ())
^
1 error

Does E not inherit the values() method of the enumeration type?

There is no values method in java.lang.Enum.
Is there some other way I can do this?

Pass a Class<E extends Enum<E>> as enumType to your constructor.

Replace "E.values()" with enumType.getEnumConstants().
I'm also rather unclear on why various JDK classes use
<E extends Enum<E>> for their parameter; I can't quite seem to
grasp what it means. I tried just using <E extends Enum>, but the
compiler had the same complaint.

Enum has generic parameter, so that needs to be supplied.

Enum requires a generic parameter so that it can implement Comparable
correctly, and declare its getDeclaringClass method.

Tom Hawtin
 
L

Lasse Reichstein Nielsen

Eric Smith said:
I'm trying to write a generic class using an enumeration as a type
parameter, but I ran into trouble trying to iterate over the enumeration
values:

class Foo<E extends Enum<E>> ....
for (E index: E.values ()) ....
The compiler says:

Foo.java:55: cannot find symbol
symbol : method values()
location: class java.lang.Enum<E>
for (E index: E.values ())
^
1 error

Does E not inherit the values() method of the enumeration type?

No. First of all, static methods are never inherited.
Second, E here is a type variable with Enum as an upper bound,
so at best it can be used to access static methods on the Enum
class. Enum has no method called "values". The only static
method is "valueOf(Class said:
Is there some other way I can do this?

No. The code you have displayed have no chance of knowing the
type parameter "E" at runtime. You need to have access to an
actual value of that type, or the class object for it, in order
to use reflection.
I'm also rather unclear on why various JDK classes use
<E extends Enum<E>> for their parameter; I can't quite seem to
grasp what it means. I tried just using <E extends Enum>, but the
compiler had the same complaint.

That's because Enum itself is parameterized. It's a hack that attempts
to introduce self-types to Java classes.

It allows inherited methods to have the correct type for subtypes.
For Enum, the method signature for "compareTo(E)" is inherited, but
each concrete Enum type must specify their own type for "E" to be
comparable to each other. This is achieved by having, e.g.,
enum Foo { BAR, BAZ}
be implemented by a class of type "Foo extends Enum<Foo>". This way,
the subclass passes back its own type to the superclass signature
it inherits.

/L
 
E

Eric Smith

I said:
I'm also rather unclear on why various JDK classes use
<E extends Enum<E>> for their parameter; I can't quite seem to
grasp what it means. I tried just using <E extends Enum>, but the
compiler had the same complaint.
That's because Enum itself is parameterized. It's a hack that attempts
to introduce self-types to Java classes.

It allows inherited methods to have the correct type for subtypes.
For Enum, the method signature for "compareTo(E)" is inherited, but
each concrete Enum type must specify their own type for "E" to be
comparable to each other. This is achieved by having, e.g.,
enum Foo { BAR, BAZ}
be implemented by a class of type "Foo extends Enum<Foo>". This way,
the subclass passes back its own type to the superclass signature
it inherits.

Thanks for the explanation. I don't think I understand it 100%, but
I'm closer.

I can understand parameterized types of the form <E1 extends SomeClass<E2>>.
It's just <E1 extends SomeClass<E1>> that seems quite confusing.

Eric
 
E

Eric Smith

Lasse said:
No. The code you have displayed have no chance of knowing the
type parameter "E" at runtime. You need to have access to an
actual value of that type, or the class object for it, in order
to use reflection.

OK. So EnumMap is able to figure out the range of the Enum type
parameter only because the constructors get the class object
at runtime? And from the class object, it has to use reflection
to get the enumeration values?

Thanks,
Eric
 
L

Lasse Reichstein Nielsen

Eric Smith said:
OK. So EnumMap is able to figure out the range of the Enum type
parameter only because the constructors get the class object
at runtime?
Yes.

And from the class object, it has to use reflection to get the
enumeration values?

Actually, the Class<T> object has the method "T[] getEnumConstants()"
that returns the values of an enum type (or null, if the Class is not
an enum), so reflection isn't needed anyway. I hadn't noticed that
method before today :)

/L
 
L

Lew

Lasse said:
Actually, the Class<T> object has the method "T[] getEnumConstants()"
that returns the values of an enum type (or null, if the Class is not
an enum), so reflection isn't needed anyway.

That /is/ reflection.
 
Y

ylandrin

Lasse said:
Actually, the Class<T> object has the method "T[] getEnumConstants()"
that returns the values of an enum type (or null, if the Class is not
an enum), so reflection isn't needed anyway.

That /is/ reflection.

Hummmm... not exactly. getEnumConstants() is only available (i.e.
returns something other than null)
when the class *is* an Enum class. Not really the behavior you expect
from reflection, that should be
independant from hypotheses on the nature of the class, and report
type-checking failures through
a few, well-defined runtime exceptions.

In my opinion, this is rather a hack to implement inheritance-aware
static fields,
in the particular case of <E extends Enum<E>> E
valueOf(Class<E>,String). Look at the implementation of Enum-related
methods in Class... you could do the same thing with a static
Map<Class<? extends Enum>,Enum[]>,
that would let you implement <E extends Enum<E>> E[] values(Class<E>),
but with much less performance.
And what object is Class-common, but updated/able whith inheritance?
The Class object, of course!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top