Duplicate :
|
|
Relates :
|
|
Relates :
|
A DESCRIPTION OF THE REQUEST : Currently, the method "public T[] getEnumConstants()" in java.lang.Class returns a clone of the values array of an enumeration class. Presumably it does so to prevent the caller from altering the enumeration values. However, this is quite inefficient if the caller is merely trying to obtain the Nth enumeration constant from the values array. Adding another method "public T getEnumConstant(int N)" would return the Nth enumerated constant without requiring the values array to be cloned (since no reference to the array would escape the method). (Returning null if N < 0 or N >= values.length, or if the class is not an enumeration, seems appropriate.) JUSTIFICATION : I'm writing a method to obtain the Nth enumeration value of an arbitrary enumeration. I'm not able to simply use the values() method implicitly available for every enumeration because the particular enumeration is not available at compile time. Instead, I'm given a Class<T> where <T extends Enum<T>>, and an integer value, i.e. public static <T extends Enum<T>> T verifyEnum(Class<T> type, int value) { return type.getEnumConstants()[value]; // error checking omitted } However, this results in a clone operation of the values array every time it is called. (And the HotSpot JIT isn't smart enough to see that the only usage of the cloned array is read-only, and therefore the original array could be used, avoiding the clone operation.) Implementing a "getEnumConstant" method provides a simple way to avoid the cloning operation. EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - I would like to simply write: public static <T extends Enum<T>> T verifyEnum(Class<T> type, int value) { return type.getEnumConstant(value); } which would call the following new method in java.lang.Class: public T[] getEnumConstant(int N) { if (enumConstants == null) { if (!isEnum()) return null; try { final Method values = getMethod("values"); java.security.AccessController.doPrivileged (new java.security.PrivilegedAction() { public Object run() { values.setAccessible(true); return null; } }); enumConstants = (T[])values.invoke(null); } // These can happen when users concoct enum-like classes // that don't comply with the enum spec. catch (InvocationTargetException ex) { return null; } catch (NoSuchMethodException ex) { return null; } catch (IllegalAccessException ex) { return null; } } if (N < 0 || N >= enumConstants.length) return null; else return enumConstants[N]; } Obviously you would refactor the common code which obtains enumConstants the first time. ---------- BEGIN SOURCE ---------- public static synchronized <T extends Enum<T>> T verifyEnum(Class<T> type, int value) { return type.getEnumConstants()[value]; } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : I cache all enum constant arrays being returned in a HashMap so that subsequent calls don't have the cloning overhead, as follows: protected static final Map<Class<? extends Enum>, List> enumConstantMap; static { enumConstantMap = new WeakHashMap<Class<? extends Enum>, List>(); } public static synchronized <T extends Enum<T>> T verifyEnum(Class<T> type, int value) { List enumConstants = enumConstantMap.get(type); if (enumConstants == null) { enumConstants = new ArrayList<T>(Arrays.asList(type.getEnumConstants())); enumConstantMap.put(type, enumConstants); } if (value < 0 || value >= enumConstants.size()) { return null; } return type.cast(enumConstants.get(value)); }
|