如何创建通用的枚举类型转换器?

4

我希望编写一个通用类,可以像这样使用:new EnumConverter(MyEnum.class);

但是如何编写这个类,使其可以与对enum.values()的泛型调用一起工作呢?

public class EnumConverter {
    public EnumConverter(Class<Enum<?>> type) {
        this.type = type;
    }

    public EnumConverter convert(String text) {
        //error: Type mismatch: cannot convert from element type capture#1-of ? to Enum<?>
        for (Enum<?> candidate : type.getDeclaringClass().getEnumConstants()) {
            if (candidate.name().equalsIgnoreCase(text)) {
                return candidate;
            }
        }
    }
}

这是什么类型的变量this.type?它是如何声明的? - flo
你的转换方法有问题,它应该返回 EnumConverter,而 candidate 的类型是 Enum<?> - bachr
我认为这是一个构造函数。 - Stewart
我对问题的意思绝对不清楚。 - Stewart
好问题。这个问题是相关的,但又不同:https://dev59.com/A2865IYBdhLWcg3wCqLI (请不要把这个评论理解为“嘿,这个问题是重复的!”) - kevinarpe
5个回答

5
您的方法“convert”的返回类型有误:应该是枚举,而不是枚举转换器(EnumConverter)。此外,您不需要调用getDeclaringClass(),而是使用已经在类型中拥有的Class即可。
我建议采用更加通用的方法:
public static class EnumConverter<T extends Enum<T>>
{

    Class<T> type;

    public EnumConverter(Class<T> type)
    {
        this.type = type;
    }

    public Enum<T> convert(String text)
    {
        for (Enum<T> candidate : type.getEnumConstants()) {
            if (candidate.name().equalsIgnoreCase(text)) {
                return candidate;
            }
        }

        return null;
    }
}

这可能是我正在寻找的东西。但是,这个能进一步优化吗?因为我需要将类型参数作为泛型参数和构造函数参数提供,例如 new EnumConverter(MyEnum.class); 或者 new EnumConverter<MyEnum>(); - membersound
使用这个类和使用 Enum.valueOf((Class<T> enumType, String name) 有什么区别? - Nick Holt
在撰写这个答案时,我不知道 Enum.valueOf() 方法,只是想展示如何让他的方法起作用。也许你可以用它来跟踪转换的过程;-) - flo
@membersound 可以通过在一个通用的静态方法中进行转换来进一步优化。但是你也可以直接使用 Enum.valueOf()。 - flo

5

您的问题不一致且无效:

1)此处未定义this.type作为一个字段。

2)您在定义convert函数时返回了EnumConverter,但实际上应该返回一个Enum

要从文本中返回枚举值,您无需使用泛型,只需要简单地使用以下代码:

Enum.valueOf(MyEnum.class, "TWO")

2
将两个最佳答案结合起来,您可以得到一个简洁的一行代码:
public <T extends Enum<T>> T getEnumValue(Class<T> type, String str) {
    return Enum.valueOf(type, str);
}

在编译时不知道类型的情况下,有没有办法使用这个?例如,Class<?> type - trebor

0
以下虽然不是一个类,但相比其他答案仍然有所改进,因为它不会产生任何警告(Java 11/IDEA 2020)。
    static <Dest extends Enum<Dest>> Dest
    convertEnumStrict(final Class<Dest> destinationClassType, final Enum<?> sourceEnum) {
        if (sourceEnum == null) {
            return null;
        }
        return Dest.valueOf(destinationClassType, sourceEnum.name());
    }

    static <Dest extends Enum<Dest>> Dest
    convertEnumOrNull(final Class<Dest> destinationClassType, final Enum<?> sourceEnum) {
        try {
            return convertEnumStrict(destinationClassType, sourceEnum);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

-1

如果有人正在寻找不使用for循环的替代解决方案。

   // classType is target Enum
     public static Enum<?> toEnum(final Class<? extends Enum> classType, final Enum<?> enumObj) {
            if (enumObj == null) {
                return null;
            } else {
                return enumObj.valueOf(classType, enumObj + "");
            }

使用方法:

 TestEnum1 enum1 = (TestEnum1) toEnum(TestEnum1.class, TestEnum1.HELLO_ENUM);

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