【问题标题】:How can I get Enum fields names using reflection in Java?如何使用 Java 中的反射获取枚举字段名称?
【发布时间】:2015-05-12 18:34:49
【问题描述】:

这是我的课:

public enum Currency {
    NIS, USD, EUR, GBP, JPY, AUD, CAD, DKK, NOK, ZAR, SEK, CHF, JOD, LBP, EGP;

    private String name;
    private int unit;
    private String country;
    private double rate;
    private double change;
}

当我尝试使用反射获取此类的字段名称时,我得到了私有字段和枚举常量(NIS、EUR、....)

如何只获取私有字段名称?

【问题讨论】:

  • 嗯?枚举至少从 1.6 开始就带有方法
  • @kolossus 因为它们实际上是被引入的:Java 5。
  • 您的字段没有任何值,为什么要访问它们?如果您计划通过反射运行时设置值,您可能需要重新考虑您的设计。枚举应该是编译时常量。
  • 为您的字段添加普通 getter 有什么问题?
  • 使用Field.getModifiers() 获取字段并选择您想要的字段。 (虽然我怀疑您可能想要不是枚举常量的每个字段,而不仅仅是私有字段,所以您可能想要Field.isEnumConstant()。)

标签: java reflection enums


【解决方案1】:

更新

根据您的评论,尝试以下操作。如果您有任何public 字段,它也不会获取任何字段。

    Field[] allFields = Currency.class.getDeclaredFields();
    for (Field field : allFields) {
        if (Modifier.isPrivate(field.getModifiers())) {
            System.out.println(field.getName());
        }
    }

结果:

要从结果中删除 $VALUES,请检查该字段是否不是合成的

    Field[] allFields = Currency.class.getDeclaredFields();
    for (Field field : allFields) {
        if (Modifier.isPrivate(field.getModifiers()) && !field.isSynthetic()) {
            System.out.println(field.getName());
        }
    }

结果:

就为这些字段赋值和访问它们而言,您不需要进行反射来执行此操作。您只需要为每个枚举适当地定义字段,如下所示。

public enum Currency {
    NIS("Name1", 0, "NIS", 1, 2), 
    USD("Name2", 1, "USD", 1, 2), 
    EUR("Name3", 2, "EUR", 1, 2), 
    GBP("Name4", 3, "GBP", 1, 2), 
    JPY("Name5", 4, "JPY", 1, 2), 
    AUD("Name6", 5, "AUD", 1, 2), 
    CAD("Name7", 6, "CAD", 1, 2), 
    DKK("Name8", 7, "DKK", 1, 2), 
    NOK("Name9", 8, "NOK", 1, 2), 
    ZAR("Name10", 9, "ZAR", 1, 2), 
    SEK("Name11", 10, "SEK", 1, 2), 
    CHF("Name12", 11, "CHF", 1, 2), 
    JOD("Name13", 12, "JOD", 1, 2), 
    LBP("Name14", 13, "LBP", 1, 2), 
    EGP("Name15", 14, "EGP", 1, 2);

    private final String name;
    private final int unit;
    private final String country;
    private final double rate;
    private final double change;

    private Currency(String name, int unit, String country, double rate, double change) {
        this.name = name;
        this.unit = unit;
        this.country = country;
        this.rate = rate;
        this.change = change;
    }

    public String getName() {
        return name;
    }

    public int getUnit() {
        return unit;
    }

    public String getCountry() {
        return country;
    }

    public double getRate() {
        return rate;
    }

    public double getChange() {
        return change;
    }
}

这个的用法是:

public static void main(String[] args) throws Exception {
    for (Currency currency : Currency.values()) {
        System.out.println("Name: " + currency.getName());
        System.out.println("Unit: " + currency.getUnit());
        System.out.println("Country: " + currency.getCountry());
        System.out.println("Rate: " + currency.getRate());
        System.out.println("Change: " + currency.getChange());
        System.out.println("");
    }
}

结果(并非所有结果都显示):

或者你可以直接使用枚举如下:

System.out.println(Currency.AUD.getName() + " " + Currency.AUD.getCountry());

结果:

Name6 澳元

【讨论】:

    【解决方案2】:

    试试测试Field.isEnumConstant()

    您还可以检查getModifiers() 并测试它是否是静态的、私有的等。

    还可能需要isSynthetic() 进行测试。

    【讨论】:

    【解决方案3】:

    这段代码应该这样做(基于bayou.io的回答):

    List<String> fields = Arrays.stream(Currency.class.getDeclaredFields())
            .filter(x -> !x.isEnumConstant() && !x.isSynthetic())
            .map(x -> x.getName())
            .collect(Collectors.toList());
    

    它只是迭代所有字段,过滤那些既不是枚举常量也不是合成的字段(如$VALUES 字段)。

    【讨论】:

    • 他们在Field 中确实有一个晦涩的方法:)不过我想知道它是如何实现的。
    • 是的,但它错过了“$VALUES”字段。
    • 使用isSynthetic()大概可以过滤掉
    • OP 只想要私有字段名称。如果枚举中有公共字段名称,这将不起作用。
    猜你喜欢
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    相关资源
    最近更新 更多