简体   繁体   English

如何在 Java 中获取 static class 成员的枚举?

[英]How to get an enum of static class members in Java?

I have a Java class (which I do not control and cannot modify) which has a large number of static String members.我有一个 Java class(我不控制也不能修改)它有大量的 static String 成员。 How can I have these as an enum (for convenience in coding)?我怎样才能将这些作为枚举(为了编码方便)?

Eg I have:例如我有:

public class ClassWithStaticMembers {
  public static String ONE = "one";
  public static String TWO = "dos";
}

...and I want to derive the following from it: ...我想从中得出以下结论:

public enum NUMBERS {
  ONE,
  TWO
}

Is this possible, with reflection or otherwise?这是可能的,有反射或其他方式吗?

(Assume I don't know Java well, and that I have 100+ values, so repeating each is painful and not desirable (in case more values get added later). Also I don't need the actual values from the class ("one" and "dos" above)). (假设我不太了解 Java,并且我有 100 多个值,所以重复每个值是痛苦的,也是不可取的(以防以后添加更多值)。而且我不需要 class 中的实际值(“一个”和上面的“dos”))。

To make it simple: Enum are statically described so there isn't any possibility to create it by reflection.为简单起见:枚举是静态描述的,因此不可能通过反射创建它。

You can still create an enumeration that wraps your constants, and optionally had a unit test (that uses reflection) to ensure that your enum is complete.您仍然可以创建一个枚举来包装您的常量,并且可以选择进行单元测试(使用反射)以确保您的枚举是完整的。

public enum NumbersEnumeration {
  ONE(ClassWithStaticMembers.ONE),
  TWO(ClassWithStaticMembers.TWO);
  private static final String name;
  public String getName(){return name};
  public NumbersEnumeration(String name){this.name=name;}
}


public class NumbersEnumerationTest{

  @Test
  public void checkEnumComplete() throws Exception{
    var fields = List.of(ClassWithStaticMembers.class.getDeclaredFields());
    for( var field:fields){
      Assertions.assertNotNull(NumbersEnumeration.valueof(field.getName());
    }
  }
}

(there may be compilation problems on reflection but you got the idea) (反射可能存在编译问题,但你明白了)

You can obtain java.lang.reflect.Field instances representing fields defined by your class using Class.getDeclaredFields() and filter out those that marked as static and access their values.您可以使用Class.getDeclaredFields()获取表示由 class 定义的字段的java.lang.reflect.Field实例,并过滤掉标记为static的字段并访问它们的值。

But the problem is that getDeclaredFields() does not guarantee that an array it returns would be ordered in any particular way.问题是getDeclaredFields()保证它返回的数组将以任何特定方式排序。 Here's a quote from the documentation :这是文档中的引述:

The elements in the returned array are not sorted and are not in any particular order .返回数组中的元素未排序未按任何特定顺序排列

So if you were thinking about associating static fields and enum members automatically based on their order of declaration, then it wouldn't work, Reflection API can't help here.因此,如果您正在考虑根据声明的顺序自动关联 static 字段和枚举成员,那是行不通的,反射 API 在这里帮不上忙。

I would advise introducing a separate utility-class which would wrap a Map associating string values and enum constants.我建议引入一个单独的实用程序类,它将包装一个Map关联字符串值和枚举常量。

public class NumbersUtils {
    public static final Map<String, Numbers> NUMBERS = Map.ofEntries(
        Map.entry("one", Numbers.ONE),
        Map.entry("dos", Numbers.TWO),
        ...
    );
    
    private NumbersUtils() {} // utility classes are not meant to be instantiated

    public static Numbers toNumber(String str) {
        if (!NUMBERS.containsKey(str)) throw new IllegalStateException(); // or remove this line if you don's want to throw in such case, method would return null instead
        
        return NUMBERS.get(str);
    }
}

Even if you have a possibility of modifying the enum, probably it would be better to keep this logic outside the enum and within the enum you can introduce a method delegating to NumbersUtils.toNumber()即使您有可能修改枚举,最好将此逻辑保留在枚举之外,而在枚举内您可以引入一个委托给NumbersUtils.toNumber()的方法

Sidenotes:旁注:

  • If these static strings and enums in your code represent the same thing in different languages, and they are mean to facilitate internationalization of the application, then keeping hard-coded strings you might want to get familiar with the proper I18N technics (through properties files and ResourceBundle s).如果代码中的这些 static 字符串和枚举在不同语言中表示相同的东西,并且它们旨在促进应用程序的国际化,那么保留硬编码字符串您可能希望熟悉正确的 I18N 技术(通过properties文件和ResourceBundle包)。 This tutorial will give a general idea on that topic. 本教程将给出关于该主题的总体思路。

  • Try to adhere to the [Java language naming conventions][conventions] while writing code.在编写代码时尽量遵守[Java 语言命名约定][约定]。 Names enums (as well as classes and interfaces) should newer be written in uppercase.名称枚举(以及类和接口)应该更新为大写。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM