Search code examples
javaclassenumsruntimeenum-map

Cannot instantiate EnumMap with dynamic class argument for enums with methods


I stumbled across a strange difference in behaviour between enums in Java without any defined methods and those that do: In the latter case, Enum.class and Enum.getClass() actually refer to different compiled classes, i.e. !Enum.class.equals(Enum.getClass()); This causes problems when trying to e.g. instantiate an EnumMap with a class specified only at runtime:

import java.util.EnumMap;

public class EnumMapTest {

    private enum TestEnum {
        FOO;
    }

    private enum TestEnumWithMethod {
        BAR {
            @Override
            protected void doSomething() {
            }
        };

        protected abstract void doSomething();
    }

    public static void main(String[] args) {
        System.out.println(String.format("Testing enum %s...", TestEnum.class));

        final Class<TestEnum> enumStaticClass = TestEnum.class;
        System.out.println(String.format("EnumMap construction using static %s...", enumStaticClass));
        new EnumMap<TestEnum, Object>(enumStaticClass);

        final Class<TestEnum> enumDynamicClass = (Class<TestEnum>) TestEnum.FOO.getClass();
        System.out.println("Are the static and dynamic classes equal? " + enumStaticClass.equals(enumDynamicClass));
        System.out.println(String.format("EnumMap construction using dynamic %s...", enumDynamicClass));
        new EnumMap<TestEnum, Object>(enumDynamicClass);


        System.out.println(String.format("Testing enum %s...", TestEnumWithMethod.class));

        final Class<TestEnumWithMethod> enumWithMethodStaticClass = TestEnumWithMethod.class;
        System.out.println(String.format("EnumMap construction using static %s...", enumWithMethodStaticClass));
        new EnumMap<TestEnumWithMethod, Object>(enumWithMethodStaticClass);

        final Class<TestEnumWithMethod> enumWithMethodDynamicClass = (Class<TestEnumWithMethod>) TestEnumWithMethod.BAR.getClass();
        System.out.println("Are the static and dynamic classes equal? " + enumWithMethodStaticClass.equals(enumWithMethodDynamicClass));
        System.out.println(String.format("EnumMap construction using dynamic %s...", enumWithMethodDynamicClass));
        new EnumMap<TestEnumWithMethod, Object>(enumWithMethodDynamicClass);
    }
}

The corresponding console output is:

Testing enum class EnumMapTest$TestEnum...
EnumMap construction using static class EnumMapTest$TestEnum...
Are the static and dynamic classes equal? true
EnumMap construction using dynamic class EnumMapTest$TestEnum...
Testing enum class EnumMapTest$TestEnumWithMethod...
EnumMap construction using static class EnumMapTest$TestEnumWithMethod...
Are the static and dynamic classes equal? false
EnumMap construction using dynamic class EnumMapTest$TestEnumWithMethod$1...
Exception in thread "main" java.lang.NullPointerException
    at java.util.EnumMap.initialization(EnumMap.java:726)
    at java.util.EnumMap.<init>(EnumMap.java:395)
    at EnumMapTest.main(EnumMapTest.java:46)

Why are there two classes made for the enum with methods? Why does this cause problems during the instantiation of EnumMap? How can I get around this to create an instance without knowing the exact enum type at compile time?


Solution

  • I found the problem: Enum.getClass() gets the anonymous class of the particular enum instance, e.g. FOO or BAR, while Enum.getDeclaringClass() gets the class of the actual enum. Strange that the latter stills works without methods, though...