简体   繁体   English

如何实现Java Enumeration Abstract类和接口?

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

I have the following problem. 我有以下问题。 I have a package with different enumeration classes in java. 我在java中有一个包含不同枚举类的包。

What is the correct approach to avoid repeting myself when adding new methods that are common to all enums? 在添加所有枚举常用的新方法时,避免重复自己的正确方法是什么?

My problem: 我的问题:

channel.java channel.java

    public enum Channel {
           channel1, channel2;
    }

color.java color.java

    public enum color{
           color1, color2;
    }

The method which should be used in both: 应该用于两者的方法:

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

Note that the loop has a reference to the enum itself. 请注意,循环具有对枚举本身的引用。 So, this will require copy and paste the method in all enums that I want to use it. 因此,这需要将方法复制并粘贴到我想要使用它的所有枚举中。 Any suggestion? 有什么建议吗?

Thanks Victor 谢谢Victor

You can't do it quite the way you want to unfortunately. 你不能以你想要的方式做到这一点。 What you can do is to have some sort of util class that has a general mehod on it. 可以做的是有某种UTIL类的在其上有一个普遍mehod。

For example... 例如...

public class EnumUtils {

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

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

Then you could use it like this... 然后你可以像这样使用它......

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

Caveat - In more complex systems, these sorts of static util classes are sometimes a bit of a "code-smell" but I think in your case it's fine. 警告 - 在更复杂的系统中,这些类型的静态util类有时候会有一些“代码味道”,但我认为在你的情况下它很好。

For Java6: 对于Java6:

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

I suggest to use an util-method like @Phil Anderson mentioned. 我建议使用像@Phil Anderson这样的@Phil Anderson方法。 I would only change it to a general pattern: 我只会将其改为一般模式:

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
    }
}

which in case of contains semantic could look like this: 在包含语义的情况下,它可能如下所示:

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;
}

Updated: 更新:

As @phil-anderson mentioned, from performance point of view this method have certain disadvantages, because generation and throwing of exception is pretty slow (see How slow are Java exceptions? ). 正如@phil-anderson提到的,从性能的角度来看,这种方法有一定的缺点,因为异常的生成和抛出相当慢(请参阅Java异常有多慢? )。 But this is only a case, if method is invoked with an incorrect name value. 但这只是一种情况,如果使用不正确的name值调用方法。

So, in this case you could use this pattern: 因此,在这种情况下,您可以使用此模式:

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
}

Moreover, if performance plays an important role, especially if enum consists of large number of values, it is not efficient to iterate over (maybe) all of them. 此外,如果性能起着重要作用,特别是如果枚举由大量值组成,那么迭代(可能)所有这些值都是无效的。 The solution could be using a lazy hash map for enums and get the value by a hashcode. 解决方案可以是为枚举使用惰性哈希映射,并通过哈希码获取值。 For example: 例如:

@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
    }
}

You can use an interface with a static method to do this: 您可以使用具有静态方法的接口来执行此操作:

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

And you both your enums can implement this interface to gain this method, although I'm not sure why you would want a method like this on your Color enum. 你们两个你的枚举都可以实现这个接口来获得这个方法,虽然我不确定你为什么要在你的Color枚举上想要这样的方法。

EDIT: 编辑:

On clarification of the question I this question will help you: Iterate enum values using java generics 在澄清问题时我会回答这个问题: 使用java泛型迭代枚举值

With reflection one can fetch the enum constants. 使用反射,可以获取枚举常量。

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);
}

As you want to access a field, it is easier to pass the entire predicate. 当您想要访问字段时,传递整个谓词会更容易。

Under java 7 one would do it generally more tight (without Stream) and need an interface for getName() etcetera. 在java 7下,人们通常会更紧凑(没有Stream)并且需要getName()等接口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用Java中的接口从超类实现抽象函数 - How to implement an abstract function from a super class with an interface in java 如何在 java 的抽象 class 中实现接口和扩展线程 - How to implement interface AND extend a thread in an abstract class in java 如何使用Java中的非抽象类实现ActionListener - How do I implement ActionListener with a non abstract class in Java 在Java中继承抽象类时是否需要再次实现接口的所有方法? - Do i need to implement all the methods of interface again while inheriting abstract class in Java? 为什么Java中的许多Collection类都会扩展抽象类并实现接口? - Why do many Collection classes in Java extend the abstract class and implement the interface as well? Java-抽象类和接口 - Java - abstract class and interface 使用抽象类实现接口 - Using Abstract Class to Implement Interface 如何用Java中的接口替换抽象类? - How to substitute an abstract class with an interface in Java? java中的抽象class和接口如何实现抽象? - How abstract class and interface achieve abstraction in java? 扩展抽象 class 的 class 是否仍然必须实现抽象 class 正在实现的接口?:Z93F725A07423FE1C8486ZD4 - Does a class which is extending an abstract class still has to implement the interface that abstract class is implementing?: java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM