在Java枚举中覆盖valueof()和toString()

Wil*_*Boy 113 java enums overriding tostring value-of

我的值enum是需要在其中包含空格的单词,但枚举不能在其值中包含空格,因此它们全部聚集在一起.我想覆盖toString()添加这些空格我告诉它.

当我使用valueOf()添加空格的相同字符串时,我还希望枚举能够提供正确的枚举.

例如:

public enum RandomEnum
{
     StartHere,
     StopHere
}
Run Code Online (Sandbox Code Playgroud)

呼叫toString()RandomEnum,其值是StartHere返回字符串"Start Here".调用valueof()相同的字符串("Start Here")返回枚举值StartHere.

我怎样才能做到这一点?

Jug*_*hah 181

你可以试试这段代码.由于您无法覆盖valueOf方法,因此您必须定义一个自定义方法(getEnum在下面的示例代码中),该方法返回您需要的值并更改您的客户端以使用此方法.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private String value;

    RandomEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }

    public static RandomEnum getEnum(String value) {
        for(RandomEnum v : values())
            if(v.getValue().equalsIgnoreCase(value)) return v;
        throw new IllegalArgumentException();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在您无法将valueOf()方法的调用更改为getValue()的情况下不起作用,例如,当您通过Hibernate注释定义某些字段以映射到枚举值时 (10认同)
  • 如果执行以下操作,可以缩短getEnum:v.getValue().equals(value); 可以省略空检查. (4认同)

小智 22

试试这个,但我不确定每个地方都会有效:)

public enum MyEnum {
    A("Start There"),
    B("Start Here");

    MyEnum(String name) {
        try {
            Field fieldName = getClass().getSuperclass().getDeclaredField("name");
            fieldName.setAccessible(true);
            fieldName.set(this, name);
            fieldName.setAccessible(false);
        } catch (Exception e) {}
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么我是唯一一个看起来邪恶的东西呢?我的意思是它看起来很酷但是没有上下文读取该代码的人很可能就像"WTF?". (15认同)
  • @NicolasGuillaume这是一种代码,如果实现,将迫切需要一个注释来解释它为什么存在以及程序员试图解决的问题.:-) (10认同)
  • 不要捕获泛型异常,因为这可能是OutOfMemory或_anything_ (8认同)
  • 这是一个可怕的想法。其中最重要的是可能出现无提示或无恢复的静默错误。现在“名称”值和代码中的符号值(例如 A、B)是不同的。+2 聪明。-200 非常聪明。我永远不会批准这个代码审查。 (3认同)

ped*_*rro 12

您可以在枚举中使用静态Map将字符串映射到枚举常量.在'getEnum'静态方法中使用它.这样就无需在每次想要从String值中获取枚举时遍历枚举.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private final String strVal;
    private RandomEnum(String strVal) {
        this.strVal = strVal;
    }

    public static RandomEnum getEnum(String strVal) {
        if(!strValMap.containsKey(strVal)) {
            throw new IllegalArgumentException("Unknown String Value: " + strVal);
        }
        return strValMap.get(strVal);
    }

    private static final Map<String, RandomEnum> strValMap;
    static {
        final Map<String, RandomEnum> tmpMap = Maps.newHashMap();
        for(final RandomEnum en : RandomEnum.values()) {
            tmpMap.put(en.strVal, en);
        }
        strValMap = ImmutableMap.copyOf(tmpMap);
    }

    @Override
    public String toString() {
        return strVal;
    }
}
Run Code Online (Sandbox Code Playgroud)

只需确保地图的静态初始化发生在枚举常量的声明之下.

顺便说一句 - 'ImmutableMap'类型来自Google guava API,我肯定会在这样的情况下推荐它.


编辑 - 根据评论:

  1. 此解决方案假定每个分配的字符串值都是唯一且非空.鉴于枚举的创建者可以控制它,并且该字符串对应于唯一和非null的枚举值,这似乎是一个安全的限制.
  2. 我按照问题中的要求添加了'toSTring()'方法

  • 对于具有相同“值”的**多个**枚举常量(如“RestartHere(“重播”),ReplayHere(“重播”)”或根本没有“值”(如“PauseHere,WaitHere”)(即枚举)的场景,这将失败有一个默认构造函数,例如“private RandomEnum() { this.strVal = null; }” (2认同)

lrn*_*grm 12

Java 8实现怎么样?(null可以替换为您的默认枚举)

public static RandomEnum getEnum(String value) {
    List<RandomEnum> list = Arrays.asList(RandomEnum.values());
    return list.stream().filter(m -> m.value.equals(value)).findAny().orElse(null);
}
Run Code Online (Sandbox Code Playgroud)

或者您可以使用:

...findAny().orElseThrow(NotFoundException::new);
Run Code Online (Sandbox Code Playgroud)