{"id":1750,"date":"2023-03-26T21:27:06","date_gmt":"2023-03-26T13:27:06","guid":{"rendered":"https:\/\/www.appblog.cn\/?p=1750"},"modified":"2023-04-23T21:27:51","modified_gmt":"2023-04-23T13:27:51","slug":"java-dynamically-modifying-enum-instances","status":"publish","type":"post","link":"https:\/\/www.appblog.cn\/index.php\/2023\/03\/26\/java-dynamically-modifying-enum-instances\/","title":{"rendered":"Java\u52a8\u6001\u4fee\u6539Enum\u5b9e\u4f8b"},"content":{"rendered":"<p>\u4f17\u6240\u5468\u77e5\uff0c<code>enum<\/code>\u7c7b\u578b\u5b9e\u4f8b\u6570\u91cf\u662f\u56fa\u5b9a\u7684\uff0c\u751a\u81f3\u8fd8\u88ab\u7528\u6765\u8bbe\u8ba1\u5355\u4f8b\u3002\u4f46\u6709\u65f6\u5019\u4ecd\u7136\u5b58\u5728\u9700\u8981\u52a8\u6001\u589e\u52a0Enum\u5b9e\u4f8b\u7684\u573a\u666f\uff0c\u8fd9\u4e5f\u5e76\u975e\u4e00\u5b9a\u662f\u8bbe\u8ba1\u5931\u8d25\uff0c\u4e5f\u53ef\u80fd\u662f\u589e\u52a0\u7075\u6d3b\u6027\u7684\u5b9e\u9645\u9700\u6c42\uff0c\u6bd4\u5982\u4e00\u4e9bweb\u6846\u67b6\u3002\u7136\u800c\u6700\u5927\u7684\u969c\u788d\u662f<code>switch<\/code>\u8bed\u53e5\u751f\u6210\u7684\u865a\u6784\u7c7b\uff0c\u672c\u6587\u53c2\u8003<code>Java Specialists<\/code>\u7b2c161\u671f\uff0c\u63d0\u4f9b\u4e00\u4efd\u53ef\u7528\u7684\u89e3\u51b3\u65b9\u6848\u4e0e\u5b9e\u4f8b\u4ee3\u7801\u3002<\/p>\n<h2>\u4e00\u6bb5\u6709\u95ee\u9898\u7684\u4ee3\u7801<\/h2>\n<p><!-- more --><\/p>\n<p>\u6bd4\u5982\u6211\u4eec\u6709\u4e00\u4e2aenum\u7c7b\u578b\uff1a<\/p>\n<pre><code class=\"language-java\">public enum HumanState\n{\n    HAPPY, SAD\n}<\/code><\/pre>\n<p>\u6211\u4eec\u662f\u8fd9\u6837\u8c03\u7528\u7684\uff1a<\/p>\n<pre><code class=\"language-java\">public class Human\n{\n    public void sing(HumanState state)\n    {\n        switch (state)\n        {\n            case HAPPY:\n                singHappySong();\n                break;\n            case SAD:\n                singDirge();\n                break;\n            default:\n                new IllegalStateException(&quot;Invalid State: &quot; + state);\n        }\n    }\n\n    private void singHappySong()\n    {\n        System.out.println(&quot;When you&#039;re happy and you know it ...&quot;);\n    }\n\n    private void singDirge()\n    {\n        System.out.println(&quot;Don&#039;t cry for me Argentina, ...&quot;);\n    }\n}<\/code><\/pre>\n<p>\u95ee\u9898\u5728\u54ea\u91cc\uff1f\u5982\u679c\u4f60\u4f7f\u7528Intelij IDEA\u7684\u8bdd\uff0c\u4f60\u5927\u6982\u4f1a\u5f97\u5230\u4e00\u4e2a\u53cb\u597d\u7684\u63d0\u793a\uff1a<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/www.yezhou.me\/AppBlog\/images\/Java\/\u679a\u4e3eswitch\u7684default\u5206\u652f\u63d0\u793a.jpg\" alt=\"\u679a\u4e3eswitch\u7684default\u5206\u652f\u63d0\u793a\" \/><\/p>\n<p>\u4e0d\u8fc7\u4f60\u53ef\u80fd\u4f1a\u8bf4\uff0c\u8fd9\u4e2a<code>switch<\/code>\u5206\u652f\u201c\u6c38\u8fdc\u201d\u4e0d\u4f1a\u88ab\u89e6\u53d1\uff0c\u5c31\u7b97\u8fd9\u53e5\u6709\u95ee\u9898\u4e5f\u65e0\u4f24\u5927\u96c5\uff0c\u751a\u81f3\u8fd9\u4e2a<code>default<\/code>\u5206\u652f\u6839\u672c\u6ca1\u6709\u5b58\u5728\u7684\u5fc5\u8981\u3002<\/p>\n<p>\u771f\u7684\u5417\uff1f<\/p>\n<h3>\u89e6\u53d1\u4e0d\u53ef\u80fd\u7684switch\u5206\u652f<\/h3>\n<p><code>Enum<\/code>\u7c7b\u4e5f\u662f\u7c7b\uff0c\u65e2\u7136\u662f\u7c7b\uff0c\u5c31\u80fd\u901a\u8fc7\u53cd\u5c04\u6765\u521b\u5efa\u5b9e\u4f8b\uff0c\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u8bd5\u8bd5\u3002<\/p>\n<pre><code class=\"language-java\">Constructor cstr = HumanState.class.getDeclaredConstructor(\n        String.class, int.class\n);\nReflectionFactory reflection =\n        ReflectionFactory.getReflectionFactory();\nHumanState e =\n        (HumanState) reflection.newConstructorAccessor(cstr).newInstance(new Object[]{&quot;ANGRY&quot;, 3});\nSystem.out.printf(&quot;%s = %d\\n&quot;, e.toString(), e.ordinal());\n\nHuman human = new Human();\nhuman.sing(e);<\/code><\/pre>\n<h3>\u8fd0\u884c\u7ed3\u679c<\/h3>\n<p>\u7ed3\u679c\u51fa\u4e4e\u610f\u6599\uff1a<\/p>\n<pre><code>ANGRY = 3\nException in thread &quot;main&quot; java.lang.ArrayIndexOutOfBoundsException: 3\n    at com.hankcs.Human.sing(Human.java:21)\n    at com.hankcs.FireArrayIndexException.main(FireArrayIndexException.java:36)\n    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n    at java.lang.reflect.Method.invoke(Method.java:483)\n    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)<\/code><\/pre>\n<p>\u672c\u6765\u6307\u671b\u53d1\u751f<code>IllegalStateException<\/code>\uff0c\u600e\u4e48\u51fa\u4e86\u4e00\u4e2a<code>ArrayIndexOutOfBoundsException<\/code>\uff1f<\/p>\n<h2>\u63a2\u7d22\u95ee\u9898<\/h2>\n<p>\u867d\u7136\u6211\u4eec\u6210\u529f\u5730\u521b\u5efa\u4e86\u4e00\u4e2a\u65b0\u7684<code>Enum<\/code>\u5b9e\u4f8b\uff0c\u4f46\u6211\u4eec\u5374\u6570\u7ec4\u8d8a\u754c\u4e86\u3002<code>stacktrace<\/code>\u6307\u51fa\u95ee\u9898\u53d1\u751f\u5728\uff1a<\/p>\n<pre><code class=\"language-java\">switch (state)<\/code><\/pre>\n<p>\u8fd9\u4e00\u53e5\uff0c\u6211\u4eec\u4e0d\u59a8\u770b\u770b\u8fd9\u4e00\u53e5\u7f16\u8bd1\u540e\u662f\u4ec0\u4e48\u6837\u5b50\u7684\u3002\u501f\u52a9IDEA\u7684\u53cd\u7f16\u8bd1\u63d2\u4ef6\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u7f16\u8bd1\u540e\u53cd\u7f16\u8bd1\u56de\u6765\u7684\u4ee3\u7801\uff1a<\/p>\n<pre><code class=\"language-java\">public class Human {\n    public Human() {\n    }\n\n    public void sing(HumanState state) {\n        class Human$1 {\n            static {\n                try {\n                    $SwitchMap$com$hankcs$HumanState[HumanState.HAPPY.ordinal()] = 1;\n                } catch (NoSuchFieldError var2) {\n                    ;\n                }\n\n                try {\n                    $SwitchMap$com$hankcs$HumanState[HumanState.SAD.ordinal()] = 2;\n                } catch (NoSuchFieldError var1) {\n                    ;\n                }\n\n            }\n        }\n        switch(Human$1.$SwitchMap$com$hankcs$HumanState[state.ordinal()]) {\n            case 1:\n                this.singHappySong();\n                break;\n            case 2:\n                this.singDirge();\n                break;\n            default:\n                new IllegalStateException(&quot;Invalid State: &quot; + state);\n        }\n\n    }\n\n    private void singHappySong() {\n        System.out.println(&quot;When you\\&#039;re happy and you know it ...&quot;);\n    }\n\n    private void singDirge() {\n        System.out.println(&quot;Don\\&#039;t cry for me Argentina, ...&quot;);\n    }\n}<\/code><\/pre>\n<p>\u539f\u6765\u5728<code>switch<\/code>\u5206\u652f\u524d\u9762\u521b\u5efa\u4e86\u4e00\u4e2a\u9759\u6001\u5185\u90e8\u7c7b\uff08\u5176\u5b9e\u662f<code>synthetic<\/code>\u7c7b\uff09\uff0c\u8be5\u5185\u90e8\u7c7b\u6709\u4e00\u4e2a\u9759\u6001<code>final<\/code>\u6570\u7ec4\uff0c\u8be5\u6570\u7ec4\u201c\u7f13\u5b58\u201d\u4e86\u7f16\u8bd1\u65f6\u7684\u6240\u6709<code>Enum<\/code>\u5bf9\u8c61\u7684<code>ordinal<\/code>\u3002\u5f53\u6211\u4eec\u901a\u8fc7\u53cd\u5c04\u65b0\u589e<code>Enum<\/code>\u5bf9\u8c61\u540e\uff0c\u8be5\u6570\u7ec4\u5e76\u6ca1\u6709\u5f97\u5230\u66f4\u65b0\uff0c\u6240\u4ee5\u53d1\u751f\u4e86\u6570\u7ec4\u4e0b\u6807\u8d8a\u754c\u7684\u5f02\u5e38\u3002<\/p>\n<h2>\u89e3\u51b3\u95ee\u9898<\/h2>\n<h3>\u4fee\u6539final static\u57df<\/h3>\n<pre><code class=\"language-java\">\/**\n * \u4fee\u6539final static\u57df\u7684\u53cd\u5c04\u5de5\u5177\n * @author hankcs\n *\/\npublic class ReflectionHelper\n{\n    private static final String MODIFIERS_FIELD = &quot;modifiers&quot;;\n\n    private static final ReflectionFactory reflection =\n            ReflectionFactory.getReflectionFactory();\n\n    public static void setStaticFinalField(\n            Field field, Object value)\n            throws NoSuchFieldException, IllegalAccessException\n    {\n        \/\/ \u83b7\u5f97 public \u6743\u9650\n        field.setAccessible(true);\n        \/\/ \u5c06modifiers\u57df\u8bbe\u4e3a\u975efinal,\u8fd9\u6837\u5c31\u53ef\u4ee5\u4fee\u6539\u4e86\n        Field modifiersField =\n                Field.class.getDeclaredField(MODIFIERS_FIELD);\n        modifiersField.setAccessible(true);\n        int modifiers = modifiersField.getInt(field);\n        \/\/ \u53bb\u6389 final \u6807\u5fd7\u4f4d\n        modifiers &amp;= ~Modifier.FINAL;\n        modifiersField.setInt(field, modifiers);\n        FieldAccessor fa = reflection.newFieldAccessor(\n                field, false\n        );\n        fa.set(null, value);\n    }\n}<\/code><\/pre>\n<h3>\u4fee\u6539\u6d89\u53caEnum\u7684switch\u5206\u652f<\/h3>\n<p>\u65e2\u7136\u8fd9\u4e2a\u7f13\u5b58\u6570\u7ec4\u662f\u53eb<code>$SwitchMap$HumanState<\/code>\uff0c\u6211\u4eec\u9700\u8981\u4fee\u6539\u6240\u6709\u4ee5<code>$SwitchMap$+Enum<\/code>\u540d\u79f0\u7684\u57df\u3002<\/p>\n<p>\u53c2\u8003\u539f\u4f5c\u8005\u5199\u4e86\u4e00\u4e2a\u5b9e\u73b0\u7c7b\uff08\u6211\u4e3b\u8981\u4fee\u6539\u4e86\u865a\u6784\u7c7b\u7684\u83b7\u53d6\u65b9\u6cd5\uff0c\u4ee5\u9002\u5e94jdk8\uff09\uff1a<\/p>\n<pre><code class=\"language-java\">package com.hankcs;\n\nimport sun.reflect.*;\n\nimport java.lang.reflect.*;\nimport java.util.*;\n\n\/**\n * \u52a8\u6001\u4fee\u6539Enum\u7684\u5bf9\u8c61\n * @param &lt;E&gt;\n *\/\npublic class EnumBuster&lt;E extends Enum&lt;E&gt;&gt;\n{\n    private static final Class[] EMPTY_CLASS_ARRAY =\n            new Class[0];\n    private static final Object[] EMPTY_OBJECT_ARRAY =\n            new Object[0];\n\n    private static final String VALUES_FIELD = &quot;$VALUES&quot;;\n    private static final String ORDINAL_FIELD = &quot;ordinal&quot;;\n\n    private final ReflectionFactory reflection =\n            ReflectionFactory.getReflectionFactory();\n\n    private final Class&lt;E&gt; clazz;\n\n    private final Collection&lt;Field&gt; switchFields;\n\n    private final Deque&lt;Memento&gt; undoStack =\n            new LinkedList&lt;Memento&gt;();\n\n    \/**\n     * Construct an EnumBuster for the given enum class and keep\n     * the switch statements of the classes specified in\n     * switchUsers in sync with the enum values.\n     *\/\n    public EnumBuster(Class&lt;E&gt; clazz, Class... switchUsers)\n    {\n        try\n        {\n            this.clazz = clazz;\n            switchFields = findRelatedSwitchFields(switchUsers);\n        }\n        catch (Exception e)\n        {\n            throw new IllegalArgumentException(\n                    &quot;Could not create the class&quot;, e);\n        }\n    }\n\n    \/**\n     * Make a new enum instance, without adding it to the values\n     * array and using the default ordinal of 0.\n     *\/\n    public E make(String value)\n    {\n        return make(value, 0,\n                    EMPTY_CLASS_ARRAY, EMPTY_OBJECT_ARRAY);\n    }\n\n    \/**\n     * Make a new enum instance with the given ordinal.\n     *\/\n    public E make(String value, int ordinal)\n    {\n        return make(value, ordinal,\n                    EMPTY_CLASS_ARRAY, EMPTY_OBJECT_ARRAY);\n    }\n\n    \/**\n     * Make a new enum instance with the given value, ordinal and\n     * additional parameters.  The additionalTypes is used to match\n     * the constructor accurately.\n     *\/\n    public E make(String value, int ordinal,\n                  Class[] additionalTypes, Object[] additional)\n    {\n        try\n        {\n            undoStack.push(new Memento());\n            ConstructorAccessor ca = findConstructorAccessor(\n                    additionalTypes, clazz);\n            return constructEnum(clazz, ca, value,\n                                 ordinal, additional);\n        }\n        catch (Exception e)\n        {\n            throw new IllegalArgumentException(\n                    &quot;Could not create enum&quot;, e);\n        }\n    }\n\n    \/**\n     * This method adds the given enum into the array\n     * inside the enum class.  If the enum already\n     * contains that particular value, then the value\n     * is overwritten with our enum.  Otherwise it is\n     * added at the end of the array.\n     * &lt;p\/&gt;\n     * In addition, if there is a constant field in the\n     * enum class pointing to an enum with our value,\n     * then we replace that with our enum instance.\n     * &lt;p\/&gt;\n     * The ordinal is either set to the existing position\n     * or to the last value.\n     * &lt;p\/&gt;\n     * Warning: This should probably never be called,\n     * since it can cause permanent changes to the enum\n     * values.  Use only in extreme conditions.\n     *\n     * @param e the enum to add\n     *\/\n    public void addByValue(E e)\n    {\n        try\n        {\n            undoStack.push(new Memento());\n            Field valuesField = findValuesField();\n\n            \/\/ we get the current Enum[]\n            E[] values = values();\n            for (int i = 0; i &lt; values.length; i++)\n            {\n                E value = values[i];\n                if (value.name().equals(e.name()))\n                {\n                    setOrdinal(e, value.ordinal());\n                    values[i] = e;\n                    replaceConstant(e);\n                    return;\n                }\n            }\n\n            \/\/ we did not find it in the existing array, thus\n            \/\/ append it to the array\n            E[] newValues =\n                    Arrays.copyOf(values, values.length + 1);\n            newValues[newValues.length - 1] = e;\n            ReflectionHelper.setStaticFinalField(\n                    valuesField, newValues);\n\n            int ordinal = newValues.length - 1;\n            setOrdinal(e, ordinal);\n            addSwitchCase();\n        }\n        catch (Exception ex)\n        {\n            throw new IllegalArgumentException(\n                    &quot;Could not set the enum&quot;, ex);\n        }\n    }\n\n    \/**\n     * We delete the enum from the values array and set the\n     * constant pointer to null.\n     *\n     * @param e the enum to delete from the type.\n     * @return true if the enum was found and deleted;\n     * false otherwise\n     *\/\n    public boolean deleteByValue(E e)\n    {\n        if (e == null) throw new NullPointerException();\n        try\n        {\n            undoStack.push(new Memento());\n            \/\/ we get the current E[]\n            E[] values = values();\n            for (int i = 0; i &lt; values.length; i++)\n            {\n                E value = values[i];\n                if (value.name().equals(e.name()))\n                {\n                    E[] newValues =\n                            Arrays.copyOf(values, values.length - 1);\n                    System.arraycopy(values, i + 1, newValues, i,\n                                     values.length - i - 1);\n                    for (int j = i; j &lt; newValues.length; j++)\n                    {\n                        setOrdinal(newValues[j], j);\n                    }\n                    Field valuesField = findValuesField();\n                    ReflectionHelper.setStaticFinalField(\n                            valuesField, newValues);\n                    removeSwitchCase(i);\n                    blankOutConstant(e);\n                    return true;\n                }\n            }\n        }\n        catch (Exception ex)\n        {\n            throw new IllegalArgumentException(\n                    &quot;Could not set the enum&quot;, ex);\n        }\n        return false;\n    }\n\n    \/**\n     * Undo the state right back to the beginning when the\n     * EnumBuster was created.\n     *\/\n    public void restore()\n    {\n        while (undo())\n        {\n            \/\/\n        }\n    }\n\n    \/**\n     * Undo the previous operation.\n     *\/\n    public boolean undo()\n    {\n        try\n        {\n            Memento memento = undoStack.poll();\n            if (memento == null) return false;\n            memento.undo();\n            return true;\n        }\n        catch (Exception e)\n        {\n            throw new IllegalStateException(&quot;Could not undo&quot;, e);\n        }\n    }\n\n    private ConstructorAccessor findConstructorAccessor(\n            Class[] additionalParameterTypes,\n            Class&lt;E&gt; clazz) throws NoSuchMethodException\n    {\n        Class[] parameterTypes =\n                new Class[additionalParameterTypes.length + 2];\n        parameterTypes[0] = String.class;\n        parameterTypes[1] = int.class;\n        System.arraycopy(\n                additionalParameterTypes, 0,\n                parameterTypes, 2,\n                additionalParameterTypes.length);\n        Constructor&lt;E&gt; cstr = clazz.getDeclaredConstructor(\n                parameterTypes\n        );\n        return reflection.newConstructorAccessor(cstr);\n    }\n\n    private E constructEnum(Class&lt;E&gt; clazz,\n                            ConstructorAccessor ca,\n                            String value, int ordinal,\n                            Object[] additional)\n            throws Exception\n    {\n        Object[] parms = new Object[additional.length + 2];\n        parms[0] = value;\n        parms[1] = ordinal;\n        System.arraycopy(\n                additional, 0, parms, 2, additional.length);\n        return clazz.cast(ca.newInstance(parms));\n    }\n\n    \/**\n     * The only time we ever add a new enum is at the end.\n     * Thus all we need to do is expand the switch map arrays\n     * by one empty slot.\n     *\/\n    private void addSwitchCase()\n    {\n        try\n        {\n            for (Field switchField : switchFields)\n            {\n                int[] switches = (int[]) switchField.get(null);\n                switches = Arrays.copyOf(switches, switches.length + 1);\n                ReflectionHelper.setStaticFinalField(\n                        switchField, switches\n                );\n            }\n        }\n        catch (Exception e)\n        {\n            throw new IllegalArgumentException(\n                    &quot;Could not fix switch&quot;, e);\n        }\n    }\n\n    private void replaceConstant(E e)\n            throws IllegalAccessException, NoSuchFieldException\n    {\n        Field[] fields = clazz.getDeclaredFields();\n        for (Field field : fields)\n        {\n            if (field.getName().equals(e.name()))\n            {\n                ReflectionHelper.setStaticFinalField(\n                        field, e\n                );\n            }\n        }\n    }\n\n    private void blankOutConstant(E e)\n            throws IllegalAccessException, NoSuchFieldException\n    {\n        Field[] fields = clazz.getDeclaredFields();\n        for (Field field : fields)\n        {\n            if (field.getName().equals(e.name()))\n            {\n                ReflectionHelper.setStaticFinalField(\n                        field, null\n                );\n            }\n        }\n    }\n\n    private void setOrdinal(E e, int ordinal)\n            throws NoSuchFieldException, IllegalAccessException\n    {\n        Field ordinalField = Enum.class.getDeclaredField(\n                ORDINAL_FIELD);\n        ordinalField.setAccessible(true);\n        ordinalField.set(e, ordinal);\n    }\n\n    \/**\n     * Method to find the values field, set it to be accessible,\n     * and return it.\n     *\n     * @return the values array field for the enum.\n     * @throws NoSuchFieldException if the field could not be found\n     *\/\n    private Field findValuesField()\n            throws NoSuchFieldException\n    {\n        \/\/ first we find the static final array that holds\n        \/\/ the values in the enum class\n        Field valuesField = clazz.getDeclaredField(\n                VALUES_FIELD);\n        \/\/ we mark it to be public\n        valuesField.setAccessible(true);\n        return valuesField;\n    }\n\n    private Collection&lt;Field&gt; findRelatedSwitchFields(\n            Class[] switchUsers)\n    {\n        Collection&lt;Field&gt; result = new LinkedList&lt;Field&gt;();\n        try\n        {\n            for (Class switchUser : switchUsers)\n            {\n                String name = switchUser.getName();\n                int i = 0;\n                while (true)\n                {\n                    try\n                    {\n                        Class suspect = Class.forName(String.format(&quot;%s$%d&quot;, name, ++i));\n                        Field[] fields = suspect.getDeclaredFields();\n                        for (Field field : fields)\n                        {\n                            String fieldName = field.getName();\n                            if (fieldName.startsWith(&quot;$SwitchMap$&quot;) &amp;&amp; fieldName.endsWith(clazz.getSimpleName()))\n                            {\n                                field.setAccessible(true);\n                                result.add(field);\n                            }\n                        }\n                    }\n                    catch (ClassNotFoundException e)\n                    {\n                        break;\n                    }\n                }\n            }\n        }\n        catch (Exception e)\n        {\n            throw new IllegalArgumentException(\n                    &quot;Could not fix switch&quot;, e);\n        }\n        return result;\n    }\n\n    private void removeSwitchCase(int ordinal)\n    {\n        try\n        {\n            for (Field switchField : switchFields)\n            {\n                int[] switches = (int[]) switchField.get(null);\n                int[] newSwitches = Arrays.copyOf(\n                        switches, switches.length - 1);\n                System.arraycopy(switches, ordinal + 1, newSwitches,\n                                 ordinal, switches.length - ordinal - 1);\n                ReflectionHelper.setStaticFinalField(\n                        switchField, newSwitches\n                );\n            }\n        }\n        catch (Exception e)\n        {\n            throw new IllegalArgumentException(\n                    &quot;Could not fix switch&quot;, e);\n        }\n    }\n\n    @SuppressWarnings(&quot;unchecked&quot;)\n    private E[] values()\n            throws NoSuchFieldException, IllegalAccessException\n    {\n        Field valuesField = findValuesField();\n        return (E[]) valuesField.get(null);\n    }\n\n    private class Memento\n    {\n        private final E[] values;\n        private final Map&lt;Field, int[]&gt; savedSwitchFieldValues =\n                new HashMap&lt;Field, int[]&gt;();\n\n        private Memento() throws IllegalAccessException\n        {\n            try\n            {\n                values = values().clone();\n                for (Field switchField : switchFields)\n                {\n                    int[] switchArray = (int[]) switchField.get(null);\n                    savedSwitchFieldValues.put(switchField,\n                                               switchArray.clone());\n                }\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\n                        &quot;Could not create the class&quot;, e);\n            }\n        }\n\n        private void undo() throws\n                NoSuchFieldException, IllegalAccessException\n        {\n            Field valuesField = findValuesField();\n            ReflectionHelper.setStaticFinalField(valuesField, values);\n\n            for (int i = 0; i &lt; values.length; i++)\n            {\n                setOrdinal(values[i], i);\n            }\n\n            \/\/ reset all of the constants defined inside the enum\n            Map&lt;String, E&gt; valuesMap =\n                    new HashMap&lt;String, E&gt;();\n            for (E e : values)\n            {\n                valuesMap.put(e.name(), e);\n            }\n            Field[] constantEnumFields = clazz.getDeclaredFields();\n            for (Field constantEnumField : constantEnumFields)\n            {\n                E en = valuesMap.get(constantEnumField.getName());\n                if (en != null)\n                {\n                    ReflectionHelper.setStaticFinalField(\n                            constantEnumField, en\n                    );\n                }\n            }\n\n            for (Map.Entry&lt;Field, int[]&gt; entry :\n                    savedSwitchFieldValues.entrySet())\n            {\n                Field field = entry.getKey();\n                int[] mappings = entry.getValue();\n                ReflectionHelper.setStaticFinalField(field, mappings);\n            }\n        }\n    }\n}<\/code><\/pre>\n<h3>\u8c03\u7528\u65b9\u5f0f<\/h3>\n<pre><code class=\"language-java\">EnumBuster&lt;HumanState&gt; buster =\n        new EnumBuster&lt;HumanState&gt;(HumanState.class,\n                                   Human.class);\nHumanState ANGRY = buster.make(&quot;ANGRY&quot;);\nbuster.addByValue(ANGRY);\nSystem.out.println(Arrays.toString(HumanState.values()));\n\nHuman human = new Human();\nhuman.sing(ANGRY);<\/code><\/pre>\n<h3>\u8f93\u51fa<\/h3>\n<pre><code>[HAPPY, SAD, ANGRY]<\/code><\/pre>\n<p><code>switch<\/code>\u5206\u652f\u5b8c\u7f8e\u4e86\u3002<\/p>\n<p>\u6ca1\u6709\u53d1\u751f\u5f02\u5e38\uff0c\u5176\u5b9e\u8fd9\u624d\u662f\u6700\u5927\u7684\u5f02\u5e38\uff0c\u90a3\u4e2a<code>default<\/code>\u5206\u652f\u660e\u660e\u8fdb\u53bb\u4e86\uff0c\u53ef\u5c31\u662f\u6ca1\u6709\u629b\u5f02\u5e38\u3002\u4e3a\u4ec0\u4e48\uff1f\u56e0\u4e3a\u6211\u4eec\u5fd8\u4e86\u52a0<code>throw<\/code>\u554a\uff0c\u670b\u53cb\u3002<\/p>\n<h2>Reference<\/h2>\n<p><a target=\"_blank\" rel=\"noopener\" href=\"http:\/\/www.javaspecialists.eu\/archive\/Issue161.html\">http:\/\/www.javaspecialists.eu\/archive\/Issue161.html<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4f17\u6240\u5468\u77e5\uff0cenum\u7c7b\u578b\u5b9e\u4f8b\u6570\u91cf\u662f\u56fa\u5b9a\u7684\uff0c\u751a\u81f3\u8fd8\u88ab\u7528\u6765\u8bbe\u8ba1\u5355\u4f8b\u3002\u4f46\u6709\u65f6\u5019\u4ecd\u7136\u5b58\u5728\u9700\u8981\u52a8\u6001\u589e\u52a0Enum\u5b9e\u4f8b\u7684\u573a\u666f\uff0c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[43],"tags":[],"class_list":["post-1750","post","type-post","status-publish","format-standard","hentry","category-java-basic"],"_links":{"self":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts\/1750","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/comments?post=1750"}],"version-history":[{"count":0,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/posts\/1750\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/media?parent=1750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/categories?post=1750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appblog.cn\/index.php\/wp-json\/wp\/v2\/tags?post=1750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}