是否可以在 Java 8 中扩展枚举?

2022-09-03 14:36:45

只是玩,并想出了一个甜蜜的方式,用这个Java Enum toString()方法中添加功能。enum

一些进一步的修补使我几乎可以添加一个整洁的(即不抛出异常)反向查找,但有一个问题。它报告:

error: valueOf(String) in X cannot implement valueOf(String) in HasValue
public enum X implements PoliteEnum, ReverseLookup {
overriding method is static

有没有办法?

这里的目的是静默地添加(通过接口实现,使用我在链接的答案中添加的方法)一个在不引发异常的情况下执行该函数的方法。可能吗?现在显然可以扩展 - 直到现在,我在Java方面的主要问题之一。defaultpoliteNamelookupvalueOfenum

这是我失败的尝试:

public interface HasName {

    public String name();
}

public interface PoliteEnum extends HasName {

    default String politeName() {
        return name().replace("_", " ");
    }
}

public interface Lookup<P, Q> {

    public Q lookup(P p);
}

public interface HasValue {
    HasValue valueOf(String name);
}

public interface ReverseLookup extends HasValue, Lookup<String, HasValue> {

    @Override
    default HasValue lookup(String from) {
        try {
            return valueOf(from);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

}

public enum X implements PoliteEnum/* NOT ALLOWED :( , ReverseLookup*/ {

    A_For_Ism, B_For_Mutton, C_Forth_Highlanders;
}

public void test() {
    // Test the politeName
    for (X x : X.values()) {
        System.out.println(x.politeName());
    }
    // ToDo: Test lookup
}

答案 1

你的设计过于复杂化了。如果您愿意接受只能在实例上调用方法,则整个代码可能如下所示:default

interface ReverseLookupSupport<E extends Enum<E>> {
    Class<E> getDeclaringClass();
    default E lookup(String name) {
        try {
            return Enum.valueOf(getDeclaringClass(), name);
        } catch(IllegalArgumentException ex) { return null; }
    }
}
enum Test implements ReverseLookupSupport<Test> {
    FOO, BAR
}

您可以通过以下方式对其进行测试:

Test foo=Test.FOO;
Test bar=foo.lookup("BAR"), baz=foo.lookup("BAZ");
System.out.println(bar+"  "+baz);

非投掷/接球的替代方案是:

interface ReverseLookupSupport<E extends Enum<E>> {
    Class<E> getDeclaringClass();
    default Optional<E> lookup(String name) {
        return Stream.of(getDeclaringClass().getEnumConstants())
          .filter(e->e.name().equals(name)).findFirst();
}

使用类似:

Test foo=Test.FOO;
Test bar=foo.lookup("BAR").orElse(null), baz=foo.lookup("BAZ").orElse(null);
System.out.println(bar+"  "+baz);

答案 2

在这里,基本上有两点。具体来说,它不编译的原因是8.4.8.1

如果实例方法重写静态方法,则这是编译时错误。

换句话说,枚举无法实现 HasValue,因为名称冲突。

然后还有一个更普遍的问题是,静态方法不能被“重写”。由于是编译器在 Enum 派生类本身上插入的静态方法,因此无法对其进行更改。我们也不能使用接口来解决它,因为它们没有静态方法。valueOf

在这种特定情况下,构图可以使这种事情不那么重复,例如:

public class ValueOfHelper<E extends Enum<E>> {
    private final Map<String, E> map = new HashMap<String, E>();

    public ValueOfHelper(Class<E> cls) {
        for(E e : EnumSet.allOf(cls))
            map.put(e.name(), e);
    }

    public E valueOfOrNull(String name) {
        return map.get(name);
    }
}

public enum Composed {
    A, B, C;

    private static final ValueOfHelper<Composed> HELPER = (
        new ValueOfHelper<Composed>(Composed.class)
    );

    public static Composed valueOfOrNull(String name) {
        return HELPER.valueOfOrNull(name);
    }
}

(另外,无论如何,我建议不要捕捉异常。

我意识到“你做不到”并不是一个理想的答案,但由于静态方面,我看不到解决它的方法。