Enum#values()
ある Enum の値を取得したい場合は Enum の static メソッドである values()
を使う。
public enum Fruits { APPLE, ORANGE, BANANA; } Fruits.values();
この values()
の実装は、コンパイラが生成してクラスに埋め込む。
言語仕様的には 8.9.2. Enum Body Declarations に以下のようにある
In addition, if E is the name of an enum type, then that type has the following implicitly declared static methods:
/** * Returns an array containing the constants of this enum * type, in the order they're declared. This method may be * used to iterate over the constants as follows: * * for(E c : E.values()) * System.out.println(c); * * @return an array containing the constants of this enum * type, in the order they're declared */ public static E[] values(); /** * Returns the enum constant of this type with the specified * name. * The string must match exactly an identifier used to declare * an enum constant in this type. (Extraneous whitespace * characters are not permitted.) * * @return the enum constant with the specified name * @throws IllegalArgumentException if this enum type has no * constant with the specified name */ public static E valueOf(String name);
例えば
以下のようなインターフェースがあって、
public interface Named { String getName(); }
enum で実装して、
public enum Fruits implements Named { APPLE("Apple"), ORANGE("Orange"), BANANA("Banana"); private final String name; private Fruits(String name) { this.name = name; } public String getName() { return name; } }
Named を実装した enum の要素を扱いたい場合、
public <T extends Enum<T> & Named> List<String> allFruits(Class<T> enumClass) { return Stream.of(enumClass.values()) .map(e -> e.name() + "(" + e.getName() + ")") .collect(Collectors.toList()); }
としても、enumClass.values()
はできない。
Class#getEnumConstants()
Class にある getEnumConstants()
を使えば良い。
public <T extends Enum<T> & Named> List<String> allFruits(Class<T> enumClass) { return Stream.of(enumClass.getEnumConstants()) .map(e -> e.name() + "(" + e.getName() + ")") .collect(Collectors.toList()); }
以下のように取れる。
allFruits(Fruits.class).forEach(System.out::println);
APPLE(Apple)
ORANGE(Orange)
BANANA(Banana)
getEnumConstants()
の実装はこんなふうになってた。
/** * Returns the elements of this enum class or null if this * Class object does not represent an enum type. * * @return an array containing the values comprising the enum class * represented by this Class object in the order they're * declared, or null if this Class object does not * represent an enum type * @since 1.5 */ public T[] getEnumConstants() { T[] values = getEnumConstantsShared(); return (values != null) ? values.clone() : null; } /** * Returns the elements of this enum class or null if this * Class object does not represent an enum type; * identical to getEnumConstants except that the result is * uncloned, cached, and shared by all callers. */ T[] getEnumConstantsShared() { if (enumConstants == null) { if (!isEnum()) return null; try { final Method values = getMethod("values"); java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { values.setAccessible(true); return null; } }); @SuppressWarnings("unchecked") T[] temporaryConstants = (T[])values.invoke(null); enumConstants = temporaryConstants; } // These can happen when users concoct enum-like classes // that don't comply with the enum spec. catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) { return null; } } return enumConstants; } private volatile transient T[] enumConstants = null;
ふむ。リフレクションで values
メソッド呼ぶのね。。