Friday, June 25, 2004

Magic fields in Enum

A little experiment:

public class Scratch { private static enum Fred { A; public void setOrdinal(final int ordinal) { try { final Field field = getClass().getDeclaredField("ordinal"); field.setAccessible(true); field.set(this, new Integer(ordinal)); } catch (IllegalAccessException e) { throw new Error(e); } catch (NoSuchFieldException e) { throw new Error(e); } } } public static void main(final String[] args) { final Fred fred = Fred.A; System.out.println(fred.getClass()); final Field[] fields = fred.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { System.out.println(fields[i]); } System.out.println(fred.ordinal()); System.out.println(fred); fred.setOrdinal(3); System.out.println(fred); System.out.println(fred.ordinal()); } }

The result?

class Scratch$Fred public static final Scratch$Fred Scratch$Fred.A private static final Scratch$Fred[] Scratch$Fred.$VALUES 0 A Exception in thread "main" java.lang.Error: java.lang.NoSuchFieldException: ordinal at Scratch$Fred.setOrdinal(Scratch.java:29) at Scratch.main(Scratch.java:47) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:78) Caused by: java.lang.NoSuchFieldException: ordinal at java.lang.Class.getDeclaredField(Unknown Source) at Scratch$Fred.setOrdinal(Scratch.java:20) ... 6 more

So the fields in java.lang.Enum are not real but are synthesized by the JVM. Too bad. I wanted to write a runtime-extensible enum, but it looks like I am out of luck.

Also, it looks like there is no reasonable way to do this and support switch. Either I have to do something like:

switch (fred) { case A: doA(); break; default: if (fred.ordinal() == 3) do3(); else dieDieDie(); }

Or it gets really messy:

private static final int ZERO = 0; private static final int THREE = 3; public static enum Fred { A(ZERO) } public static void play(final Fred fred) { switch (fred.ordinal()) { case ZERO: doA(); break; case THREE: do3(); break; default: dieDieDie(); } }

Not nice at all.

No comments: