Принудительная инициализация перечислимого типа в Java - PullRequest
12 голосов
/ 29 сентября 2010

Я пытаюсь найти способ заставить Java загрузить / инициализировать перечислимый тип (который вложен в класс, содержащий статическую карту).

Это важно для меня, потому что перечислимый тип имеет конструктор, который заполняет указанную карту, и без явного способа инициализации этого перечисления карта останется пустой. Я пытался использовать Class.forName, но, похоже, это не работает.

Полагаю, я мог бы создать экземпляр перечисления (и сохранить его в другой коллекции или что-то в этом роде), но я хотел бы знать, есть ли элегантный способ сделать это.

Ответы [ 4 ]

10 голосов
/ 29 сентября 2010

Класс загружается, когда вы ссылаетесь на класс. Это работает одинаково для всех классов.

Скорее всего, у вас проблема в том, что значение Enum инициализируется перед любым статическим блоком. то есть вы не можете ссылаться на что-то инициализируемое в статическом блоке в конструкторе. (Обычно инициализация статического содержимого в конструкторе - ПЛОХАЯ идея) Вам нужно инициализировать карту в статическом блоке, а не в конструкторе.

Попробуйте

import java.util.Map; 
import java.util.HashMap; 

public enum EnumTest { 
  FOO, BAR, BAZ; 

  private static final Map<String,EnumTest> map = new LinkedHashMap<String,EnumTest>(); 
  static { 
      for(EnumTest e : EnumTest.values())
        map.put(e.name(), e); 
  } 

  public static void main(String... args) { 
    System.out.println(EnumTest.map); 
  } 
}
5 голосов
/ 29 сентября 2010

Разве вы не можете просто поместить инициализацию карты в статический инициализатор типа Enum?

public enum SomeEnum
{
    Member1, Member2, Member3 ...

    private static Map<K, SomeEnum> map = ...;
    static 
    {
        ...populate map...
    }
    ...

РЕДАКТИРОВАТЬ: Похоже, проблема заключалась в том, что определения членов Enum должны быть на первом месте. Я думаю, что я просто замял это. Я исправил пример.

3 голосов
/ 29 сентября 2010

Вы можете просто сослаться на что-нибудь в классе enum. Например:

public class EnumTest {
  static final Map<String, MyEnum> map = new HashMap<String, MyEnum>();

  enum MyEnum {
    FOO, BAR, BAZ;

    MyEnum() {
      map.put(name(), this);
    }
  }
  static {
    // ensure MyEnum is initialized
    MyEnum.values();
  }

  public static void main(String[] argsa) {
    System.out.println(map.size());
  }
}
2 голосов
/ 29 сентября 2010

Похоже, именно поэтому часто рекомендуется использовать методы доступа вместо прямых ссылок на члены. Ваша проблема в том, что код разрешает доступ к карте до ее инициализации. Заблокируйте произвольный доступ к карте и спрячьте ее за методом доступа, который обеспечивает ее инициализацию.

import java.util.Map;
import java.util.HashMap;

public enum EnumTest {
  FOO, BAR, BAZ;

  private static Map<String,EnumTest> map = null;

  public synchronized static Map getMap() {
    if (map == null) {
      map = new HashMap<String,EnumTest>();
      for ( EnumTest e : EnumTest.values() ) {
        map.put( e.name(), e );
      }
    }

    return map;
  }

  public static void main(String[] args) {
    System.out.println( EnumTest.getMap().size() );
  }
}
...