获取枚举下变量的值

3
我想将枚举的常量及其变量的值写入文件或打印出来。
例如,这是我想要实现的方法:
id, field_name_1, field_name_2, ...
enum_id, field_value_1, field_value_2, ...
...

然而,我不太确定如何做到这一点,因为我最近才开始使用反射。这是我当前的代码。
public static void writeEnum(String filename, Enum e, SnelPlugin plugin){
        SnelTextFile file = new SnelTextFile(plugin, new File(plugin.getDataFolder() + "/" + filename + ".txt"));
        Logger.debug("Starting an EnumWriter for " + filename + ".txt for plugin " + plugin.getPluginName());

    try {
        file.openWriter(true);

        Field[] fields = e.getClass().getFields();

        // HEADER
        String info = "";
        for(Field f: fields) {
            info += ", " + f.getName();
            Logger.debug("Detected value: " + f.getName());
        }
        info = info.replaceFirst(", ", "");
        file.addLine(info);

        // CONTENT
        for(Object current: e.getDeclaringClass().getEnumConstants()){
            Logger.debug(current.toString());

            String result = "";

            for(Field f: fields){
                result += ", " + f.get(current);
            }

            result = result.replaceFirst(", ", "");

            file.addLine(result);

            Logger.debug("Added row: " + result);
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }finally {
        try {
            file.closeWriter();
        } catch (IOException e1) {
        }
    }

    Logger.log(LColor.GREEN + "Finished an EnumWriter action on " + filename + ".txt from " + plugin.getPluginName());
}

这是我为了进行简单测试而设置的枚举(APIPerm):
COMMANDS_SNELAPI,
COMMANDS_SNELAPI_INFO;

private String id;

APIPerm(){
    id = getID();
}

@Override
public String getPrefix() {
    return "snelapi";
}

@Override
public String getID(){
    return getPrefix() + "." + this.toString().toLowerCase().replaceAll("_", ".");
}

然而,在for(Object current: e.getDeclaringClass().getEnumConstants())中我得到了一个NPE(空指针异常)。
谢谢你的帮助, Sneling。

@MarkusFischer 如果“e”为空,我们将在早期得到NPE。因此,看起来“getEnumConstants()”是罪魁祸首。但这也没有太多意义,因为OP要求从“e”中是某个枚举类的实例,因此该枚举类必须至少有一个枚举常量(作为参数传递的那个)。 - Pshemo
我不确定如何帮助你,因为我不知道你期望的确切结果,也无法从你的问题中重现NPE问题。请发布你想要处理的输入/枚举类的示例(但不要将其发布为图片,我们无法将其复制到我们的IDE中)。包括你期望的结果(你可以添加一些关于为什么期望这些结果的信息)以及你实际得到的结果。如果SnelPlugin不是必需的,则减少你的代码,不要在代码中包含它。此外,并非每个人都配置了日志记录机制,为什么不使用简单的System.out呢? - Pshemo
看起来你想获取所有(不仅是公共的)非静态字段(因为它们应该属于实例,而不是类)。在这种情况下,您可能希望使用getDeclaredFields()而不是getFields()。区别在于,getFields仅返回公共字段,包括继承的字段,而getDeclaredFields()仅返回在该类中声明的字段(甚至包括私有字段 - 因此,如果您想要获取该字段的值,则可能需要在其上先调用setAccessible(true))。演示:https://ideone.com/qVkHIg - Pshemo
@Pshemo 哦,好的!那正是我想要的。我试了你的方法,它有效,现在我将尝试将其实现到我已有的方法中,并查看结果如何。如果它运行良好,你希望我发布完整的答案并在其中标记你,还是你自己来做呢? 顺便说一下,我有一个完全可用的方法,但它包含SnelPlugin和我的Logger。 - Sneling
如果可能的话,请尝试简化您的问题,例如“我想打印每个枚举常量,如果该枚举具有其字段,则为每个常量的字段值,例如[发布枚举结构和预期结果]。我尝试使用此代码[发布显示您的方法的简单代码 - “简单”避免不必要的事情,例如当我们可以简单地写入控制台时,不要写入文件],但问题是[描述您面临的问题,例如您不希望方法接受实例,因为某些枚举可能为空,您还希望能够处理它们]”。 - Pshemo
显示剩余10条评论
2个回答

1
如果您想获取枚举的值,通常只需要在枚举类上调用values()方法。但是,由于您从实例开始,所以需要获取类并调用它。我没有看到任何将类强制转换为枚举的方法,因此我使用了反射来获取public static Enum[] values()方法,如下所示。
/**
 * Get the Enum values for this Enum instance.
 * @param e the enum value
 * @return all the values for this type of enum
 */
private Enum[] getValues(Enum e) {
    Enum[] values = new Enum[0];
    try {
        Class<? extends Enum> enumClass = e.getDeclaringClass();
        Method mtd = enumClass.getMethod("values");
        values = (Enum[])mtd.invoke(null);
    }
    catch (Exception ex) {
        ex.printStackTrace();
    }
    return values;
}

显然,您应该做更好的错误处理。关于字段,我不确定您还想从Enum类中获得什么其他信息。

嘿, 感谢您的建议。我的唯一小问题是,我应该从哪里获取枚举实例,因为枚举的目标不是要做这个(...?)吗?我在没有使用您的函数的情况下测试了一个新功能,但我肯定想看看您如何充分使用它。请查看原始帖子上的我的新更新。 - Sneling
在你的代码中,一个参数是Enum e,所以我假设你有实例而不是类。如果你有枚举类,那么你可以直接调用values() - pamcevoy
为什么不使用类并使用EnumSet.allOf呢? - Mike Samuel

1

感谢 @Pshemo 和 @MarkusFisher 的帮助,我已经找到了解决方案。

请注意,该方法确实包括其他类和方法,但它们不会影响此方法的工作方式。

如果您想自行测试:

  • Logger.debug 可以替换为 System.out.println,LColor 应删除
  • SnelPlugin 仅用于 Logger.debug 和定位目录。
  • SnelTextFile 只是一个使创建文本文件更容易的类。如果只打印信息,则应将其删除。

方法代码:

public static <E extends Enum<E>> void writeEnum(String fileName, Class<E> c, SnelPlugin plugin){
    SnelTextFile file = new SnelTextFile(plugin, new File(plugin.getDataFolder() + "/" + fileName + ".txt"));
    Logger.debug("Starting EnumWriter for " + file.getFile().getName(), plugin);

    try {
        file.openWriter(true);
        Logger.debug("Opened FileWriter", plugin);

        Field[] classFields = c.getDeclaredFields();

        String header = "Value";

        for(Field f: classFields){
            if(!Modifier.isStatic(f.getModifiers())) {
                header += ", " + f.getName();
                Logger.debug("Discovered variable '" + f.getName() + "'", plugin);
            }
        }

        file.addLine(header);
        file.addLine("");

        for(E en: c.getEnumConstants()){
            Logger.debug("Reading Enum Constant: " + en.toString(), plugin);
            Field[] fields = en.getDeclaringClass().getDeclaredFields();

            String current = en.toString();

            for(Field f: fields){
                if(!Modifier.isStatic(f.getModifiers())){
                    f.setAccessible(true);
                    current += ", " + f.get(en);
                    Logger.debug("Value for '" +f.getName() + "' = '" +  f.get(en) + "'" , plugin);
                }
            }

            file.addLine(current);
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }finally {
        try {
            file.closeWriter();
            Logger.debug("Closer FileWriter");
        } catch (IOException ex) {
        }
    }

    Logger.log(LColor.GREEN + "Finished EnumWriter for " + file.getFile().getName() + ". It can be found at " + file.getFile().getPath(), plugin);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接