你如何实现一个Java Enumeration Abstract class 和接口?

How do you implement a Java Enumeration Abstract class and interface?

我有以下问题。 我在 java.

中有一个包含不同枚举 类 的包

在添加所有枚举通用的新方法时避免重复自己的正确方法是什么?

我的问题:

channel.java

    public enum Channel {
           channel1, channel2;
    }

color.java

    public enum color{
           color1, color2;
    }

两者都应该使用的方法:

    public static boolean contains(String channel) {
       for (Channel c : Channel.values()) {
          if (c.name().equals(channel)) {
              return true;
          }
      }
    return false;
    }

请注意,循环引用了枚举本身。因此,这将需要将该方法复制并粘贴到我要使用它的所有枚举中。 有什么建议吗?

谢谢 维克多

您可以使用带有静态方法的接口来执行此操作:

public interface CanContainChannel {
    static boolean contains(String channel) {
        for (Channel c : Channel.values()) {
           if (c.name().equals(channel)) {
               return true;
           }
        }
        return false;
    }
}

你们两个枚举都可以实现这个接口来获得这个方法,虽然我不确定你为什么要在你的 Color 枚举上使用这样的方法。

编辑:

关于问题的澄清我这个问题对你有帮助: Iterate enum values using java generics

不幸的是,你不能完全按照你想要的方式去做。您可以做的是拥有某种具有通用方法的实用程序class。

例如...

public class EnumUtils {

    public static boolean contains(Enum[] enumValues, String nameToCheck) {

        for(Enum each : enumValues) {
            if(each.name().equals(nameToCheck)) {
                return true;
            }
        }
        return false;
    }
}

那你就可以这样用了...

System.out.println(EnumUtils.contains(Channel.values(), "channel1")); // TRUE
System.out.println(EnumUtils.contains(Color.values(), "octarine")); // FALSE

警告 - 在更复杂的系统中,这些静态实用程序 classes 有时有点 "code-smell" 但我认为你的情况很好。

对于Java6:

     change each.name() => each.toString()

我建议使用像 @Phil Anderson 提到的实用方法。我只会将其更改为通用模式:

public static <T extends Enum<T>> void some_method(Class<T> clazz, String name) {
    try {
        T foundEnum = Enum.valueOf(clazz, name);
        // name matches to one of enum values, do something with it
    } catch (IllegalArgumentException e) {
        // name doesn't matches to any of enum values
    }
}

在包含语义的情况下可能如下所示:

public static <T extends Enum<T>> boolean contains(Class<T> clazz, String name) {
    try {
        Enum.valueOf(clazz, name);
    } catch (IllegalArgumentException e) {
        return false;
    }
    return true;
}

更新:

正如 @phil-anderson 提到的,从性能的角度来看,这种方法有一定的缺点,因为异常的生成和抛出非常慢(参见 How slow are Java exceptions?)。但这只是一种情况,如果使用不正确的 name 值调用方法。

所以,在这种情况下,您可以使用这种模式:

public static <T extends Enum<T>> void some_method(Class<T> clazz, String name) {
    for (T each : clazz.getEnumConstants()) {
        if (each.name().equals(name)) {
            // name matches to one of enum values, do something with it
        }
    }
    // name doesn't matches to any of enum values
}

此外,如果性能起着重要作用,尤其是如果枚举包含大量值,则迭代(也许)所有这些值效率不高。解决方案可能是对枚举使用惰性哈希映射并通过哈希码获取值。例如:

@SuppressWarnings("unchecked")
public static <T extends Enum<T>> void some_method(Class<T> clazz, String name) {
    Map<String, Enum<?>> enumMap = enumsMap.get(clazz);
    if (enumMap == null) {
        enumMap = new HashMap<String, Enum<?>>();
        for (T t : clazz.getEnumConstants()) {
            enumMap.put(t.name(), t);
        }
        enumsMap.put(clazz, enumMap);
    }
    T t = (T) enumMap.get(name);
    if (t != null) {
        // name matches to one of enum values, do something with it
    } else {
        // name doesn't matches to any of enum values
    }
}

通过反射可以获取枚举常量。

enum E {
    i("unu"), ii("du"), iii("tri"), iv("kvar");

    public final String name;

    E(String name) {
        this.name = name;
    }
}

public static void main(String[] args) {
    // Normally in Java 8 for a concrete enum:
    final String sought = "tri";
    boolean found = Stream.of(E.values()).anyMatch((c) -> c.name.equals(sought));

    // A generic function:
    System.out.println("okay:  "
        + find(E.class, (c) -> c.name.equals(sought)));
    System.out.println("fails: "
        + find(E.class, (c) -> c.name.equals("prtl")));
}

public static <T extends Enum<?>> boolean find(Class<T> clazz,
        Predicate<T> predicate) {
    return Stream.of(clazz.getEnumConstants()).anyMatch(predicate);
}

因为要访问一个字段,传递整个谓词更容易。

在 java 7 下,通常会更紧凑(没有 Stream)并且需要一个用于 getName() 等的接口。