2013-09-13 1 views
1

Я наткнулся на странную разницу в поведении между перечислениями на Java без каких-либо определенных методов и тех, которые делают: В последнем случае Enum.class и Enum.getClass() действительно относятся к разным скомпилированным классам, т.е. !Enum.class.equals(Enum.getClass()); Это вызывает проблемы при попытке, например, экземпляр EnumMap с классом указывается только во время выполнения:Не удается создать экземпляр EnumMap с аргументом динамического класса для перечислений с помощью методов

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); 
    } 
} 

Соответствующий выход консоли:

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) 

Почему существует два класса, сделанные для перечисления с методами? Почему это вызывает проблемы при создании EnumMap? Как я могу обойти это, чтобы создать экземпляр без знания точного типа перечисления во время компиляции?

ответ

0

Я нашел проблему: Enum.getClass() получает анонимный класс конкретного экземпляра enum, например. FOO или BAR, тогда как Enum.getDeclaringClass() получает класс фактического перечисления. Странно, что последние кадры работают без методов, хотя ...

0

Причина для нескольких классов является то, что различные enum методы реализуются путем создания анонимного внутреннего класса ($1) для каждого enum значения, так же, как если бы вы объявили некоторый встроенный ActionListener. «Обходной путь» заключается в использовании фактического класса enum (TestEnumWithMethod), а не класса значения этого перечисления; если вы знаете достаточно информации для безопасного использования EnumMap, вы знаете достаточно информации для использования «родного» типа enum.

+0

Это не мой вопрос: в моем случае у меня нет информации о классе во время компиляции. См. Мой ответ ниже – errantlinguist

+0

@errantlinguist Просьба уточнить ваш предполагаемый прецедент. Любой общий метод, который будет создавать «EnumMap» или иным образом должен знать класс «enum», должен иметь класс как вход (например, для «EnumSet # noneOf'); если вы перейдете в «BAR», вам все равно придется указывать «TestEnumWithMethod» как параметр типа для того, что вы его передаете. – chrylis

+0

Извините, вы ответили «почему» на мой вопрос, но если я опубликую текущую проблему с реализацией, я скажу, что опубликую «минимальный рабочий пример». В моем случае у меня есть контейнер экземпляров «Enum», который не является «EnumSet» - моим точным случаем, «List», потому что мне нужно заказать перечисления. Я обобщил метод работы с несколькими типами перечислений, и он работал во всех случаях, кроме тех случаев, когда перечисления имеют определенные методы. – errantlinguist

Смежные вопросы