2015-05-20 89 views
2

我有以下问题。 我有一个包含java中不同枚举类的包。如何实现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; 
    } 

注意,循环有一个参考到枚举本身。所以,这需要复制并粘贴所有我想使用它的枚举的方法。 有什么建议吗?

感谢 维克多

+0

第一个问题是为什么你首先需要这样的方法。但除此之外,在Java 8中,您可以使用接口和默认方法来实现此功能。另一个问题是否这是一个好主意。 – biziclop

+0

为什么你的Color enum需要这种方法,如果它与Color无关? – Oli

+0

@biziclop我知道这个Java8的一部分,但我仅限于Java 6这个特殊情况。 – vcaldas

回答

2

我建议使用util的法像提到@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 
    } 
} 
+0

由于某种原因,这不会产生预期的结果。我不熟悉这种结构,所以可能是我的不好。 但是,如果我尝试,例如: 包含(Channel.class,“channel1”); 我得知没有检测到任何东西。 – vcaldas

+0

如果你将contains-method放在'EnumUtil'类中,那么'System.out.println(EnumUtil.contains(Channel.class,“channel1”));''按预期返回'true'。 – olexd

+0

是一个区分大小写的问题。干杯。 – vcaldas

1

您可以使用接口与静态方法来做到这一点:

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

+0

我认为这个想法是每个枚举都有自己的方法版本,指的是它自己。另外,实现一个接口没有太多的意义,因为它只有一个静态方法,甚至不会引用接口。 – biziclop

+0

@biziclop我确实认为使用默认方法将是一种可能性,但我不确定为什么Color枚举会需要像这样的实例方法。尽管如此,你也可以使用它,它不需要像这样的静态方法。 – Oli

+0

@biziclop在他的例子中,他想要的方法都是静态的 – Oli

4

你不能做到这一点很要不幸的方法。 可以用做什么,就是拥有某种具有普通方法的util类。

例如...

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 

警告 - 在更复杂的系统中,这些各种各样的静态UTIL类是有时有点的“代码味道”,但我认为你的情况很好。

对于的Java6:

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

我认为这将会完成这项工作,我想对此进行投票,但我不能。感谢您的告诫!我对这一切都很陌生。 – vcaldas

+1

更安全的变体是为枚举传递类对象,然后使用'Class.getEnumConstants()'枚举方法中的常量。 – biziclop

+0

@vcaldas你可以接受它作为正确的答案。 – biziclop

0

使用反射可以获取枚举常量。

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()等的接口。