在Java中强制初始化枚举类型

在Java中强制初始化枚举类型,java,enums,enumeration,Java,Enums,Enumeration,我试图找到一种方法来强制Java加载/初始化枚举类型(它嵌套在包含静态映射的类中) 这对我来说很重要,因为枚举类型有一个填充所述映射的构造函数,如果没有显式方法初始化该枚举,映射将保持为空。我尝试使用Class.forName,但这似乎不起作用 我想我可以创建一个枚举实例(并将其存储在soem其他集合或其他东西中),但我想知道是否有一种优雅的方法可以做到这一点。您不能将映射的初始化放在枚举类型的静态初始值设定项中吗 public enum SomeEnum { Member1, Memb

我试图找到一种方法来强制Java加载/初始化枚举类型(它嵌套在包含静态映射的类中)

这对我来说很重要,因为枚举类型有一个填充所述映射的构造函数,如果没有显式方法初始化该枚举,映射将保持为空。我尝试使用
Class.forName
,但这似乎不起作用


我想我可以创建一个枚举实例(并将其存储在soem其他集合或其他东西中),但我想知道是否有一种优雅的方法可以做到这一点。

您不能将映射的初始化放在枚举类型的静态初始值设定项中吗

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

    private static Map<K, SomeEnum> map = ...;
    static 
    {
        ...populate map...
    }
    ...
public enum SomeEnum
{
成员1,成员2,成员3。。。
私有静态映射=。。。;
静止的
{
…填充地图。。。
}
...

编辑:问题似乎是枚举成员定义需要放在第一位。我想我只是忽略了这一点。我修复了该示例。

您可以引用枚举类中的某些内容。例如:

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());
  }
}
公共类枚举测试{
静态最终映射=新HashMap();
髓鞘{
福,巴,巴兹;;
髓鞘(){
put(name(),this);
}
}
静止的{
//确保MyEnum已初始化
MyEnum.values();
}
公共静态void main(字符串[]argsa){
System.out.println(map.size());
}
}

这似乎正是为什么经常建议使用访问器方法而不是直接引用成员的原因。您的问题是,代码允许在映射初始化之前访问映射。阻止对映射的任意访问,并将其隐藏在确保已初始化的访问器方法后面

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() );
  }
}
import java.util.Map;
导入java.util.HashMap;
公共枚举测试{
福,巴,巴兹;;
私有静态映射=null;
公共同步静态映射getMap(){
if(map==null){
map=新的HashMap();
对于(EnumTest e:EnumTest.values()){
map.put(e.name(),e);
}
}
返回图;
}
公共静态void main(字符串[]args){
System.out.println(EnumTest.getMap().size());
}
}

引用类时会加载类。这对所有类都适用

您遇到的问题更可能是枚举值在任何静态块之前初始化。即,您不能在构造函数中引用在静态块中初始化的内容。(通常在构造函数中初始化静态内容是个坏主意)您需要在静态块中初始化映射,而不是在构造函数中初始化映射

试一试

import java.util.Map;
导入java.util.HashMap;
公共枚举测试{
福,巴,巴兹;;
私有静态最终映射=新LinkedHashMap();
静态{
对于(EnumTest e:EnumTest.values())
map.put(e.name(),e);
} 
公共静态void main(字符串…参数){
System.out.println(EnumTest.map);
} 
}

这似乎无法解决问题,因为在某个枚举中创建的所有实例都是静态的。问题仍然存在:如何告诉类加载器初始化/加载枚举?一旦我解决了这个问题,所有枚举的静态代码都应该根据需要执行。那么,您可以再详细说明一下吗?这会导致什么问题?您如何解决如果枚举进行初始化,请在初始化枚举之前删除映射?映射是否不包含在枚举中?正确。映射不包含在枚举中。我无法将映射放置在枚举中,因为Java不允许枚举构造函数填充枚举中的静态集合。+1中有一个很好的示例JLS 8.9,在
enum Color
"那么,映射的目的是什么呢?我以前编写过带有内部静态映射的枚举;我想我想知道您正在尝试实现什么。如果您不能保证在需要使用映射之前构造枚举,您可能需要重新考虑您的设计,尽管Matt建议使用静态映射r可能会满足您的需要。此线程涉及主题。
Class.forName
会初始化一个类。如果它“不起作用”,您的代码会有其他您没有意识到的问题。为什么不发布您的代码。基本上我看到一个异常,说明该类“无效”,我确信我有正确的包路径。Class.forName()是否应该在所有情况下都对枚举有效?这是我正在使用的基本解决方法。但由于MyEnum.values()的返回值实际上没有在代码中使用,我担心它可能会被“优化掉”。然后,我又看到了一个类似的技巧,用于确保对常规类进行初始化,因此这可能是解决问题的一个不错的方法。我相当确定,它不能完全优化,因为它可能会导致类初始化。Java留下的“未定义”要少得多比C或C++更好,更糟。这一点看起来是最好的方法。我会给它一个镜头。BTW + 1,TrasGod,他指出了一个使用同样方法的例子。它是有效的。我同意你的说法:“在构造函数中初始化静态内容是个坏主意”。。我继续使用此方法。可能我将在Guava或Collections.unmodifiableMap中使用ImmutableMap,以防止在地图字段中添加任何在EnumTest中未实际定义的潜在项。
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); 
  } 
}