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 メソッド呼ぶのね。。