リフレクションでのEnum継承クラスのコンストラクタ

enumキーワードで宣言されるEnum継承クラス(ここではE)のコンストラクタは、リフレクションで調べると…

package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class EnumConstructorTest {
    private enum E {
        A,
        ;
        
        // 無引数に見える
        private E(){/**/}
        private E(final Number num){/**/}
        private E(final Number num1, final Number num2){/**/}
        
    }

    public static void main(final String[] args) throws InstantiationException,
            IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, NoSuchMethodException, SecurityException {
        Constructor<?>[] ctrs = E.class.getDeclaredConstructors();
        for (Constructor<?> ctr : ctrs) {
            // E(String, int) など
            System.out.println(ctr);
        }
        Constructor<E> ctr = E.class.getDeclaredConstructor(String.class, int.class);
        ctr.setAccessible(true);
        ctr.newInstance("hoge", 1);
    }
}

privateコンストラクタを定義しても先頭にString, int引数が付加される。
setAccessibleして呼び出すとIllegalArgumentExceptionが発生する。

実行結果

private test.EnumConstructorTest$E(java.lang.String,int,java.lang.Number)
private test.EnumConstructorTest$E(java.lang.String,int)
private test.EnumConstructorTest$E(java.lang.String,int,java.lang.Number,java.lang.Number)
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at test.EnumConstructorTest.main(EnumConstructorTest.java:28)

なお、E(String, int) ではなくスーパークラスのコンストラクEnum(String, int) を呼ぶとInstantiationExceptionが発生する。これはEnumがabstractだから。