只是玩游戏,然后想出一个甜蜜的方式,在Java Enum toString() method this {{}}} enum
中为error: valueOf(String) in X cannot implement valueOf(String) in HasValue
public enum X implements PoliteEnum, ReverseLookup {
overriding method is static
添加功能。
进一步的修修让我几乎也添加了一个整洁(即没有抛出异常)反向查找,但是有一个问题。据报道:
default
有办法吗?
这里的目的是默默地添加(通过界面实现,使用politeName
方法,例如我在链接的答案中添加了lookup
)valueOf
方法执行enum
函数没有抛出异常。可能吗?现在显然可以扩展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
}
- 我迄今为止的一个主要Java问题。
这是我失败的尝试:
{{1}}
答案 0 :(得分:15)
您的设计过于复杂。如果您愿意接受只能在实例上调用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);
答案 1 :(得分:0)
案例与您在界面中无法创建默认toString()
的情况相同。枚举已包含静态valueOf(String)
方法的签名,因此您无法覆盖它。
枚举是编译时常量,因此它确实有可能在某一天可扩展。
如果您想获得常量名称,可以使用:
public static <E extends Enum<E>> Optional<E> valueFor(Class<E> type, String name) {
return Arrays.stream(type.getEnumConstants()).filter( x -> x.name().equals(name)).findFirst();
}
答案 2 :(得分:0)
这里基本上有两点。具体而言,它不编译的原因是8.4.8.1:
如果实例方法覆盖静态方法,则为编译时错误。
换句话说,由于名称冲突,枚举无法实现HasValue。
然后我们遇到的更普遍的问题是静态方法不能被“覆盖”。由于valueOf
是编译器在Enum派生类本身上插入的静态方法,因此无法更改它。我们也不能使用接口来解决它,因为它们没有静态方法。
在这个特定的情况下,这是一个组合可以使这种事情少重复的地方,例如:
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);
}
}
(另外,我建议过去捕捉异常。)
我意识到“你不能做到”并不是一个理想的答案,但由于静态方面的原因,我没有找到解决方法。
答案 3 :(得分:0)
我想我有一个答案 - 它是hacky并且使用反射但似乎适合简短 - 即在枚举中没有方法的反向查找而且没有抛出异常。
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 ReverseLookup<T extends Enum<T>> extends Lookup<String, T> {
@Override
default T lookup(String s) {
return (T) useMap(this, s);
}
}
// Probably do somethiong better than this in the final version.
static final Map<String, Enum> theMap = new HashMap<>();
static Enum useMap(Object o, String s) {
if (theMap.isEmpty()) {
try {
// Yukk!!
Enum it = (Enum)o;
Class c = it.getDeclaringClass();
// Reflect to call the static method.
Method method = c.getMethod("values");
// Yukk!!
Enum[] enums = (Enum[])method.invoke(null);
// Walk the enums.
for ( Enum e : enums) {
theMap.put(e.name(), e);
}
} catch (Exception ex) {
// Ewwww
}
}
return theMap.get(s);
}
public enum X implements PoliteEnum, ReverseLookup<X> {
A_For_Ism,
B_For_Mutton,
C_Forth_Highlanders;
}
public void test() {
for (X x : X.values()) {
System.out.println(x.politeName());
}
for (X x : X.values()) {
System.out.println(x.lookup(x.name()));
}
}
打印
A For Ism
B For Mutton
C Forth Highlanders
A_For_Ism
B_For_Mutton
C_Forth_Highlanders
受@Holger的启发 - 这就是我觉得最喜欢的东西:
public interface ReverseLookup<E extends Enum<E>> extends Lookup<String, E> {
// Map of all classes that have lookups.
Map<Class, Map<String, Enum>> lookups = new ConcurrentHashMap<>();
// What I need from the Enum.
Class<E> getDeclaringClass();
@Override
default E lookup(String name) throws InterruptedException, ExecutionException {
// What class.
Class<E> c = getDeclaringClass();
// Get the map.
final Map<String, Enum> lookup = lookups.computeIfAbsent(c,
k -> Stream.of(c.getEnumConstants())
// Roll each enum into the lookup.
.collect(Collectors.toMap(Enum::name, Function.identity())));
// Look it up.
return c.cast(lookup.get(name));
}
}
// Use the above interfaces to add to the enum.
public enum X implements PoliteName, ReverseLookup<X> {
A_For_Ism,
B_For_Mutton,
C_Forth_Highlanders;
}