GitHors GitHors - 5 months ago 28
Java Question

How l can call values() from instance of generic type <E extends Enum<E>>?

public static <E extends Enum<E>> void example(E e){
e. //what should I put here to get result of values()?
}


I am trying to call the method
values()
that returns the values of an
enum
using this method with generic arguments.

How can I do that?

Answer

Enum doesn't have values() method. It is added by compiler later to each of your Enum subclasses (when we are creating your own enum YourEnum{...} type). So we can't invoke values() from Enum type.

Possible solution is

E[] values = e.getDeclaringClass().getEnumConstants();

To be safe we should use getDeclaringClass() instead of getClass(), because enum values can be implemented as anonymous classes like in case of TimeUnit

public enum TimeUnit {
    /**
     * Time unit representing one thousandth of a microsecond
     */
    NANOSECONDS {
        public long toNanos(long d)   { return d; }
        public long toMicros(long d)  { return d/(C1/C0); }
        public long toMillis(long d)  { return d/(C2/C0); }
        public long toSeconds(long d) { return d/(C3/C0); }
        public long toMinutes(long d) { return d/(C4/C0); }
        public long toHours(long d)   { return d/(C5/C0); }
        public long toDays(long d)    { return d/(C6/C0); }
        public long convert(long d, TimeUnit u) { return u.toNanos(d); }
        int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
    },

In this case

  • TimeUnit.NANOSECONDS.getClass() returns java.util.concurrent.TimeUnit$3 (but this anonymous class doesn't contain any enum values)
  • TimeUnit.NANOSECONDS.getDeclaringClass() returns java.util.concurrent.TimeUnit (with contains all of enum values).

It will also save us some trouble with casting since

  • getDeclaringClass returns Class<E>
  • getClass() returns Class<? extends E>

So result type of

  • getDeclaringClass().getEnumConstants() is E[]
  • while getClass().getEnumConstants() is ? extends Enum[].

This allows us to create loop like without need to involve casting:

for (E value : e.getDeclaringClass().getEnumConstants()){
    //handle value
}

As an extra, you can also get all values from Class<E> (where <E extends Enum<E>>) by using EnumSet.allOf(enumClass) like in case of code from this question:

EnumSet<E> allOf = EnumSet.allOf(e.getDeclaringClass());
Comments