为什么Enum会实现一个接口?

我刚刚发现Java允许枚举实现一个接口。 这将是一个很好的用例呢?

枚举不仅需要表示被动集(例如颜色)。 它们可以用function表示更复杂的对象,因此您可能希望为这些function添加更多function – 例如,您可能具有PrintableReportable等接口以及支持这些function的组件。

下面是一个例子(在Effective Java 2nd Edition中find了一个类似/更好的例子):

 public interface Operator { int apply (int a, int b); } public enum SimpleOperators implements Operator { PLUS { int apply(int a, int b) { return a + b; } }, MINUS { int apply(int a, int b) { return a - b; } }; } public enum ComplexOperators implements Operator { // can't think of an example right now :-/ } 

现在得到一个简单+复杂运算符的列表:

 List<Operator> operators = new ArrayList<Operator>(); operators.addAll(Arrays.asList(SimpleOperators.values())); operators.addAll(Arrays.asList(ComplexOperators.values())); 

所以在这里你使用一个接口来模拟可扩展的枚举(如果不使用接口,这是不可能的)。

这里几个人给出的Comparable例子是错误的,因为Enum已经实现了这个例子。 你甚至不能覆盖它。

一个更好的例子是有一个接口来定义数据types。 你可以有一个枚举实现简单的types,并有正常的类来实现复杂的types:

 interface DataType { // methods here } enum SimpleDataType implements DataType { INTEGER, STRING; // implement methods } class IdentifierDataType implements DataType { // implement interface and maybe add more specific methods } 

由于枚举可以实现接口,因此可以严格执行单例模式。 试图做一个标准的类单身人士允许…

  • 对于使用reflection技术来公开私有方法的可能性
  • 从你的单身inheritance和重写你的单身的方法与别的东西

枚举作为单例有助于防止这些安全问题。 这可能是让Enums充当类和实现接口的原因之一。 只是一个猜测。

请参阅https://stackoverflow.com/questions/427902/java-enum-singleton和java中的Singleton类以获得更多讨论。;

这是扩展性所必需的 – 如果有人使用您开发的API,您定义的枚举是静态的; 他们不能被添加或修改。 但是,如果让它实现一个接口,使用该API的人可以使用相同的接口来开发自己的枚举。 然后你可以用一个枚举pipe理器注册这个枚举,这个枚举pipe理器把枚举与标准接口集成在一起。

编辑:@Helper方法有这个完美的例子。 考虑让其他图书馆定义新的经营者,然后告诉经理类“嘿,这个枚举存在 – 注册”。 否则,你只能在自己的代码中定义运算符 – 不会有可扩展性。

有我经常使用的情况。 我有一个带有静态方法的IdUtil类来处理实现一个非常简单的可Identifiable接口的对象:

 public interface Identifiable<K> { K getId(); } public abstract class IdUtil { public static <T extends Enum<T> & Identifiable<S>, S> T get(Class<T> type, S id) { for (T t : type.getEnumConstants()) { if (Util.equals(t.getId(), id)) { return t; } } return null; } public static <T extends Enum<T> & Identifiable<S>, S extends Comparable<? super S>> List<T> getLower(T en) { List<T> list = new ArrayList<>(); for (T t : en.getDeclaringClass().getEnumConstants()) { if (t.getId().compareTo(en.getId()) < 0) { list.add(t); } } return list; } } 

如果我创build一个可Identifiable enum

  public enum MyEnum implements Identifiable<Integer> { FIRST(1), SECOND(2); private int id; private MyEnum(int id) { this.id = id; } public Integer getId() { return id; } } 

那么我可以通过它的id这样得到它:

 MyEnum e = IdUtil.get(MyEnum.class, 1); 

例如,如果你有一个logging器枚举。 然后在界面中应该有logging器方法,如debugging,信息,警告和错误。 它使你的代码松散耦合。

枚举只是变相的类,所以在大多数情况下,你可以用一个枚举来完成一个类的任何事情。

我想不出一个枚举不能实现一个接口的理由,同时我也想不出有一个好的理由。

我会说,一旦你开始添加像接口或方法的东西,你应该真的考虑把它作为一个类。 当然,我确信有非常规的非枚举types的东西是有效的,因为这个限制是假的,所以我赞成让人们在那里做他们想做的事情。

最常见的用法是将两个枚举的值合并为一个组,并以相似的方式对待它们。 例如,看看如何join水果和蔬菜 。

枚举类似Java类,它们可以有构造函数,方法等等。你不能用它做的唯一事情是new EnumName() 。 这些实例是在你的枚举声明中预定义的。

Predicatefilter是使用枚举的接口的最好用例之一。 这是一个很好的方法来弥补apache集合的缺乏(如果其他库不能使用)。

 import java.util.ArrayList; import java.util.Collection; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; public class Test { public final static String DEFAULT_COMPONENT = "Default"; enum FilterTest implements Predicate { Active(false) { @Override boolean eval(Test test) { return test.active; } }, DefaultComponent(true) { @Override boolean eval(Test test) { return DEFAULT_COMPONENT.equals(test.component); } } ; private boolean defaultValue; private FilterTest(boolean defautValue) { this.defaultValue = defautValue; } abstract boolean eval(Test test); public boolean evaluate(Object o) { if (o instanceof Test) { return eval((Test)o); } return defaultValue; } } private boolean active = true; private String component = DEFAULT_COMPONENT; public static void main(String[] args) { Collection<Test> tests = new ArrayList<Test>(); tests.add(new Test()); CollectionUtils.filter(tests, FilterTest.Active); } } 

这是我的原因

我已经用Enum的值填充了一个JavaFXcombobox。 我有一个接口,Identifiable(指定一个方法:标识),它允许我指定如何将任何对象标识为我的应用程序用于search的目的。 这个接口使我能够扫描任何types的对象的列表(无论哪个对象可以用于标识的字段)进行标识匹配。

我想在我的ComboBox列表中find一个身份值的匹配项。 为了在包含Enum值的ComboBox上使用这个function,我必须能够在Enum中实现Identifiable接口(在Enum的情况下,实现这个接口是微不足道的)。

你可以用enum来做更多的事情。 你可以添加方法和构造参数给他们。 你可以使用Comparable来比较它们。 此外, enum是类,所以应该允许接口实现。

 enum Planet implements Comparable<Planet> { EARTH(1), MARS(3); // ... and so on public final float distance; Planet(float distance) { this.distance = distance; } // compare distances public int compareTo(Planet other) { return this.distance - other.distance; } // sorry, I didnt check my code } 

我在一个接口中使用了一个内部枚举来描述一个策略来保持实例控制(每个策略都是一个单例)。

 public interface VectorizeStrategy { /** * Keep instance control from here. * * Concrete classes constructors should be package private. */ enum ConcreteStrategy implements VectorizeStrategy { DEFAULT (new VectorizeImpl()); private final VectorizeStrategy INSTANCE; ConcreteStrategy(VectorizeStrategy concreteStrategy) { INSTANCE = concreteStrategy; } @Override public VectorImageGridIntersections processImage(MarvinImage img) { return INSTANCE.processImage(img); } } /** * Should perform edge Detection in order to have lines, that can be vectorized. * * @param img An Image suitable for edge detection. * * @return the VectorImageGridIntersections representing img's vectors * intersections with the grids. */ VectorImageGridIntersections processImage(MarvinImage img); } 

枚举实现这个策略的事实很方便,让枚举类可以作为它的封闭实例的代理。 这也实现了界面。

这是一种strategyEnumProxy:P clent代码如下所示:

 VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img); 

如果它没有实现接口,它曾经是:

 VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img);