【问题标题】:Java: instantiating an enum using reflectionJava:使用反射实例化枚举
【发布时间】:2010-09-17 13:56:21
【问题描述】:

假设你有一个像这样的文本文件:

my_setting = ON
some_method = METHOD_A
verbosity = DEBUG
...

您希望相应地更新相应的对象:

Setting my_setting = ON;
Method some_method = METHOD_A;
Verbosity verbosity = DEBUG;
...

所有这些都是不同类型的枚举。

我想要一种通用的方法来实例化枚举值。也就是说,在运行时使用反射,并且事先不知道对象的枚举类型。

我会想象这样的事情:

for (ConfigLine line : lines)
{
   String[] tokens = line.string.split("=", 2);
   String name = tokens[0].trim();
   String value = tokens[1].trim();

   try
   {
      Field field = this.getClass().getDeclaredField(name);   
      if(field.getType().isEnum())
      {
         // doesn't work (cannot convert String to enum)
         field.set(this, value);
         // invalid code (some strange generics issue)
         field.set(this, Enum.valueOf(field.getType().getClass(), value));
      }
      else
      { /*...*/ }
   }
   catch //...
}

问题是:应该有什么代替?给定它的字符串表示,甚至可以实例化一个未知的枚举吗?

【问题讨论】:

    标签: java reflection enums


    【解决方案1】:
    field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value));
    
    • 不应调用 getType() 之后的 getClass() - 它返回 Class 实例的类
    • 您可以转换Class&lt;Enum&gt;,以避免一般问题,因为您已经知道Classenum

    【讨论】:

    • 这会导致泛型编译器错误:Enum 类型中的方法 valueOf(Class, String) 不适用于参数 (Class, Object)
    • field.getType().asSubclass(Enum.class) 会更好吗?
    • 如果您使用声明的字段,这将有问题 - isEnumConstant 可能不起作用。最好按照@rebzie 的建议使用 valueOf 方法调用
    【解决方案2】:

    没有强制转换的替代解决方案

    try {
        Method valueOf = field.getType().getMethod("valueOf", String.class);
        Object value = valueOf.invoke(null, param);
        field.set(test, value);
    } catch ( ReflectiveOperationException e) {
        // handle error here
    }
    

    【讨论】:

    • 我认为这是这个问题的最佳解决方案
    • 只花了两个小时试图使选定的答案起作用,但因为我没有要转换的枚举类型而无法使用 - 如果我能早点向下滚动...谢谢
    【解决方案3】:

    你有一个额外的getClass 电话,你必须施放(更具体的施放每个 Bozho):

    field.set(test, Enum.valueOf((Class<Enum>) field.getType(), value));
    

    【讨论】:

    • 泛型问题依然存在
    【解决方案4】:

    接受的答案会导致警告,因为它使用原始类型 Enum 而不是 Enum>。

    要解决这个问题,您需要使用这样的通用方法:

    @SuppressWarnings("unchecked")
    private <T extends Enum<T>> T createEnumInstance(String name, Type type) {
      return Enum.valueOf((Class<T>) type, name);
    }
    

    这样称呼它:

    Enum<?> enum = createEnumInstance(name, field.getType());
    field.set(this, enum);
    

    【讨论】:

      【解决方案5】:

      你可以像下面这样对你的枚举进行编码:

      public enum Setting {
      
          ON("ON"),OFF("OFF");
      
          private final String setting;
      
          private static final Map<String, Setting> stringToEnum = new ConcurrentHashMap<String, Setting>();
          static {
              for (Setting set: values()){
                  stringToEnum.put(set.setting, set);
              }
          }
      
          private Setting(String setting) {
              this.setting = setting;
          }
      
          public String toString(){
              return this.setting;
          }
      
          public static RequestStatus fromString(String setting){
              return stringToEnum.get(setting);
          }   
      }
      

      然后您可以轻松地从 String 中创建 Enum 而无需反射:

      Setting my_settings = Setting.fromString("ON");
      

      此解决方案并非来自我自己。我从其他地方读到它,但我不记得出处了。

      【讨论】:

      • 如果您使用反射,则不是很有帮助,因为您不知道有问题的枚举是否正在使用此设置。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      • 1970-01-01
      • 2017-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-30
      相关资源
      最近更新 更多