limitations on using enum as generic parameter


D

dalamb

I am playing around with using enums and generics together in Java 1.5
(yes, I know it's in end-of-life, but it would be a bit of trouble
right now to go to 1.6 let alone 1.7). Having figured out some simple
situations, I tried writing a generic class that takes an enum as a
type parameter. Unfortunately I don't seem to be able to invoke the
enum's values() method -- javac says "Cannot find symbol: method
values()". (the reference to Enum.valueof later also gets errors,
which is why I commented it out to simplify the test).

Is there any way around this, or is there just no way to refer to an
enum's values() method when the enum is a generic parameter?

Here's the code; interface MessageCode should be irrelevant because it
could be any old interface for the purposes of this example:

public class EnumCodeSet<E extends Enum & MessageCode>
// implements MessageCodeSet
{
private E[] enums;
public EnumCodeSet() {
enums = E.values();
}

public MessageCode get(int index)
throws IndexOutOfBoundsException
{
return enums[index];
} // get

public MessageCode valueOf(String name)
throws IllegalArgumentException, NullPointerException
{
// return Enum.valueof(E,name);
} //
} // end class EnumCodeSet
 
Ad

Advertisements

M

markspace

situations, I tried writing a generic class that takes an enum as a
type parameter. Unfortunately I don't seem to be able to invoke the
enum's values() method -- javac says "Cannot find symbol: method


Yes, values() and valueOf(String) are /static/ methods. They don't
appear on the Enum interface so the compiler doesn't know about them.

You can try object.getClass().getEnumConstants() to get the constants
themselves in order.

Also you should probably be declaring you enum as <E extends Enum<E> & ...>.

Untested:

public class EnumCodeSet<E extends Enum<E> & MessageCode>
{
private final E[] enums;

public EnumCodeSet( E anEnum ) {
enums = anEnum.getClass().getEnumConstants);
}

public MessageCode index( int i ) {
return enums;
}

//... etc.
}
 
D

Daniele Futtorovic

I am playing around with using enums and generics together in Java 1.5
(yes, I know it's in end-of-life, but it would be a bit of trouble
right now to go to 1.6 let alone 1.7). Having figured out some simple
situations, I tried writing a generic class that takes an enum as a
type parameter. Unfortunately I don't seem to be able to invoke the
enum's values() method -- javac says "Cannot find symbol: method
values()". (the reference to Enum.valueof later also gets errors,
which is why I commented it out to simplify the test).

Is there any way around this, or is there just no way to refer to an
enum's values() method when the enum is a generic parameter?

Here's the code; interface MessageCode should be irrelevant because it
could be any old interface for the purposes of this example:

public class EnumCodeSet<E extends Enum& MessageCode>
// implements MessageCodeSet
{
private E[] enums;
public EnumCodeSet() {
enums = E.values();
}

public MessageCode get(int index)
throws IndexOutOfBoundsException
{
return enums[index];
} // get

public MessageCode valueOf(String name)
throws IllegalArgumentException, NullPointerException
{
// return Enum.valueof(E,name);
} //
} // end class EnumCodeSet

HTH.

public class EnumCodeSet<E extends Enum<E> & MessageCode>
{
private final Class<E> clazz;
public EnumCodeSet( Class<E> clazz ) {
if( clazz == null ) {
throw new IllegalArgumentException( new
NullPointerException() );
}

this.clazz = clazz;
}

public MessageCode get(int index)
throws IndexOutOfBoundsException
{
return clazz.getEnumConstants()[ index ];
} // get

public MessageCode valueOf(String name)
throws IllegalArgumentException, NullPointerException
{
return Enum.valueOf(clazz, name);
} //
} // end class EnumCodeSet
 
L

Lew

situations, I tried writing a generic class that takes an enum as a
type parameter.  Unfortunately I don't seem to be able to invoke the
enum's values() method -- javac says "Cannot find symbol: method

Yes, values() and valueOf(String) are /static/ methods.  They don't
appear on the Enum interface so the compiler doesn't know about them.

You can try object.getClass().getEnumConstants() to get the constants
themselves in order.

Also you should probably be declaring you enum as <E extends Enum<E> & ....>.

Untested:

public class EnumCodeSet<E extends Enum<E> & MessageCode>
{
   private final E[] enums;

   public EnumCodeSet( E anEnum ) {
     enums = anEnum.getClass().getEnumConstants);
   }

   public MessageCode index( int i ) {
     return enums;
   }

   //... etc.


Also, generics and arrays don't mix. So don't mix them.
 
D

dalamb

Also, generics and arrays don't mix.  So don't mix them.

Uh, that's a little cryptic. I'm fairly new to Java generics (and
enums), so what's the issue with arrays and generics?
 
L

Lew

Uh, that's a little cryptic.  I'm fairly new to Java generics (and
enums), so what's the issue with arrays and generics?

"This is why creation of arrays of non-reifiable types is forbidden.
One may declare variables of array types whose element type is not
reifiable, but any attempt to assign them a value will give rise to an
unchecked warning (§5.1.9)."
JLS §10.10
http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#10.10

http://lmgtfy.com/?q=Why+don't+Java+arrays+and+generics+mix
 
Ad

Advertisements

D

Daniele Futtorovic

That's not going to work. It's a static method of a class that isn't
determined at this point in the code, so the compiler simply has no clue
what to call. Hence the error message.

If you really need to do something like this, you'll need to use
reflection on a class object.

For the record: no. See my and ninja markspace's replies.
 
D

Daniele Futtorovic

Also, generics and arrays don't mix. So don't mix them.

While that is perfectly true, I think it's mostly misleading in this
context. Arrays of enum instances are fine.
 
D

Daniele Futtorovic

I meant the general case of wanting to invoke a static method on a type
parameter, where the method depends on the run-time type (so, it's not a
method of X where you have<E extends X>, but a method implemented
differently for each choice of E).

I would argue that this would be bad design. Aside from cases where
reflection is part of the contract (Spring, for instance), it should
only be used exceptionally, if at all.
In the special case of an enum there's getEnumConstants.

Which doesn't work via reflection, FWIW.
 
Ad

Advertisements

M

markspace

I can switch to using an ArrayList, though.


You don't need to in this instance. values() and getEnumConstants()
both return an array of the proper type, so the dirty work has been done
for you.

Actually, "don't mix arrays and generics" is far to strong. There's no
reason not to mix them. There's only a couple of edge cases where you
have to do funny things with compiler directives. Your usage here is
just fine.
 
D

Daniele Futtorovic

Would you explain what you mean by that? 'getEnumConstants()' is
itself a method of reflection.

It means what it says and, upon verification, turns out to be my
mistake. I had assumed there was some VM support for the enum constants.
Hadn't checked well enough. Thanks for pointing it out.
 
L

Lew

It means what it says and, upon verification, turns out to be my

If I understood what it said, I wouldn't have had to ask.
mistake. I had assumed there was some VM support for the enum constants.
Hadn't checked well enough. Thanks for pointing it out.

What does the VM have to do with it? This is a Java question, not a
VM question.

My question is what you mean by "via reflection"? I understand the
term to mean the use of methods that reveal information about a type
without direct use of the type as such. So whatever the VM does or
does not do, 'getEnumConstants()' is a reflective method.

Because your stsatement seems well founded on an understanding that is
different from mine, I ask again what you mean.
 
D

Daniele Futtorovic

If I understood what it said, I wouldn't have had to ask.


What does the VM have to do with it? This is a Java question, not a
VM question.

My question is what you mean by "via reflection"? I understand the
term to mean the use of methods that reveal information about a type
without direct use of the type as such. So whatever the VM does or
does not do, 'getEnumConstants()' is a reflective method.

Because your stsatement seems well founded on an understanding that is
different from mine, I ask again what you mean.

Goodness, Lew! No, my statement is founded on the very same
understanding as yours. It just happens to be wrong (the statement).
Could you please stop exposing my mistake in such punctilious a manner? :)

I vaguely seemed to remember some kind of native call or the like
further down the call to #getEnumConstants. Hence the reference to the
VM. I cannot tell where I got that from, and should have challenged that
assumption. Yes, #getEnumConstants is a method that uses reflection to
achieve its function. Can I crawl back under my rock now?
 
L

Lew

Daniele said:
Goodness, Lew! No, my statement is founded on the very same
understanding as yours. It just happens to be wrong (the statement).
Could you please stop exposing my mistake in such punctilious a manner? :)

I apologize. I'm not trying to expose a mistake. I really thought there was
something there for me to learn. I'm truly sorry.

You've been here long enough to know I've made much more foolish mistakes than
yours.

--
Lew
Ceci n'est pas une fenêtre.
..___________.
|###] | [###|
|##/ | *\##|
|#/ * | \#|
|#----|----#|
|| | * ||
|o * | o|
|_____|_____|
|===========|
 
Ad

Advertisements

R

Roedy Green

(yes, I know it's in end-of-life, but it would be a bit of trouble
right now to go to 1.6 let alone 1.7

It is actually surprisingly easy. Just download the JDK. Install,
uninstall the old JDK, set JAVA_HOME, optionally recompile the
universe. Tell your IDE where your new JDK is. I have yet to find a
JDK 1.5 program that won't compile and run just fine under JDK 1.6.

I generate 1.5 class files using the JDK 1.6 compiler with -target

see http://mindprod.com/jgloss/jdk.html
 
R

Roedy Green

javac says "Cannot find symbol: method
values()". (the reference to Enum.valueof later also gets errors,
which is why I commented it out to simplify the test).

Even though enums are under the hood implemented as nested classes,
the Java language does think of enums as being classes or inheriting
from anything. You are trying to use them as if they were ordinary
classes.

To pull that off you would have to re-invent enums as ordinary
classes. To do that, have a look at the various enum decompilations I
have posted at http://mindprod.com/jgloss/enum.html
 
L

Lew

, quoted or indirectly quoted someone who said :
Roedy said:
It is actually surprisingly easy. Just download the JDK. Install,
uninstall the old JDK, set JAVA_HOME, optionally recompile the
universe. Tell your IDE where your new JDK is. I have yet to find a
JDK 1.5 program that won't compile and run just fine under JDK 1.6.

It can happen and I've seen it, but they're rare. A couple of the interfaces
have changed, notably 'javax.sql.RowSet' and 'java.sql.ResultSet'. Code that
implements that interface for Java 5 will not compile correctly for 6 unless
you implement the new methods. Also, '@Override' raises a warning if the
supertype is an interface in 5, but omitting it in that situation raises a
warning in 6.

It is quite rare to run into the former (most people don't compile their own
JDBC code, but some do). The latter is a minor annoyance.

I haven't run into other scenarios where the transition is difficult.
Normally it's as transparent as Roedy indicates.
I generate 1.5 class files using the JDK 1.6 compiler with -target

see http://mindprod.com/jgloss/jdk.html

--
Lew
Ceci n'est pas une fenêtre.
..___________.
|###] | [###|
|##/ | *\##|
|#/ * | \#|
|#----|----#|
|| | * ||
|o * | o|
|_____|_____|
|===========|
 
Ad

Advertisements

L

Lew

Even though enums are under the hood implemented as nested classes,
the Java language does think of enums as being classes or inheriting
from anything. You are trying to use them as if they were ordinary
classes.

To pull that off you would have to re-invent enums as ordinary
classes. To do that, have a look at the various enum decompilations I
have posted at http://mindprod.com/jgloss/enum.html

The 'enum' is a specialization of the "type-safe enumeration" with compiler
support. You can still implement type-safe enumerations by hand, just as
Joshua Bloch described in edition one of /Effective Java/, before Java 5.

People forget that enumerations are not limited to 'enum' exactly because
'enum' covers nearly all situations where you want a type-safe enumeration,
but in the end 'enum' is syntactic sugar for the latter. When 'enum' doesn't
do the job you roll your own, just like you use a spelled-out 'for' when a
for-each isn't enough.

--
Lew
Ceci n'est pas une fenêtre.
..___________.
|###] | [###|
|##/ | *\##|
|#/ * | \#|
|#----|----#|
|| | * ||
|o * | o|
|_____|_____|
|===========|
 

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

Top