Java:使用反射实例化枚举

发布于 2024-09-19 21:08:57 字数 962 浏览 6 评论 0 原文

假设您有一个如下文本文件:

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 //...
}

问题是:应该有什么?是否有可能根据其字符串表示来实例化一个未知的枚举?

Suppose you have a text file like:

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

That you wish to to update a corresponding object accordingly:

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

Where all are different kind of enums.

I would like to have a generic way to instantiate the enum values. That is, at runtime using reflection, and without knowing the enum types of the object in advance.

I would have imagined something like this:

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 //...
}

The question is: what should there be instead? Is it even possible to instantiate an unknown enum given its String representation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

木落 2024-09-26 21:08:57
field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value));
  • 不应调用 getType() 之后的 getClass() - 它返回 Class 实例的类
  • 您可以强制转换 Class ;,以避免通用问题,因为您已经知道 Class 是一个 enum
field.set(this, Enum.valueOf((Class<Enum>) field.getType(), value));
  • getClass() after getType() should not be called - it returns the class of a Class instance
  • You can cast Class<Enum>, to avoid generic problems, because you already know that the Class is an enum
祁梦 2024-09-26 21:08:57

无需铸造的替代解决方案

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
}

Alternative solution with no casting

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
}
空袭的梦i 2024-09-26 21:08:57

您有一个额外的 getClass 调用,并且必须进行强制转换(每个 Bozho 都有更具体的强制转换):

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

You have an extra getClass call, and you have to cast (more specific cast per Bozho):

field.set(test, Enum.valueOf((Class<Enum>) field.getType(), value));
蛮可爱 2024-09-26 21:08:57

接受的答案会导致警告,因为它使用原始类型 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);

The accepted answer results in warnings because it uses the raw type Enum instead of Enum<T extends Enum<T>>.

To get around this you need to use a generic method like this:

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

Call it like this:

Enum<?> enum = createEnumInstance(name, field.getType());
field.set(this, enum);
别忘他 2024-09-26 21:08:57

您可以对 Enum 进行类似的编码:

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

这个解决方案不是源自我自己。我是从其他地方读到的,但记不起出处了。

You may code your Enum similar tho this:

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

Then you may easily create Enum from String without reflection:

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

This solution is not originated from myself. I read it from somewhere else, but I can't recall the source.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文