[英]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.