Java 为什么 Enum 会实现接口?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2709593/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 11:07:25  来源:igfitidea点击:

Why would an Enum implement an Interface?

javaenums

提问by unj2

I just found out that Java allows enums to implement an interface. What would be a good use case for that?

我刚刚发现 Java 允许枚举实现接口。什么是一个好的用例?

采纳答案by Brian Agnew

Enums don't just have to represent passive sets (e.g. colours). They can represent more complex objects with functionality, and so you're then likely to want to add further functionality to these - e.g. you may have interfaces such as Printable, Reportableetc. and components that support these.

枚举不仅仅代表被动集(例如颜色)。他们可以代表与功能更复杂的对象,所以你可能想进一步功能添加到这些是那么-例如,你可能如接口PrintableReportable等等。支持这些和组件。

回答by TofuBeer

Enums are just classes in disguise, so for the most part, anything you can do with a class you can do with an enum.

枚举只是伪装的类,所以在大多数情况下,你可以用一个类做的任何事情都可以用一个枚举来做。

I cannot think of a reason that an enum should not be able to implement an interface, at the same time I cannot think of a good reason for them to either.

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

I would say once you start adding thing like interfaces, or method to an enum you should really consider making it a class instead. Of course I am sure there are valid cases for doing non-traditional enum things, and since the limit would be an artificial one, I am in favour of letting people do what they want there.

我想说的是,一旦您开始向枚举添加接口或方法之类的东西,您就应该真正考虑将其改为类。当然,我确信有一些有效的案例可以做非传统的枚举事情,而且由于限制是人为的,我赞成让人们在那里做他们想做的事。

回答by Chris Dennett

It's required for extensibility -- if someone uses an API you've developed, the enums you define are static; they can't be added to or modified. However, if you let it implement an interface, the person using the API can develop their own enum using the same interface. You can then register this enum with an enum manager which conglomerates the enums together with the standard interface.

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

Edit: @Helper Method has the perfect example of this. Think about having other libraries defining new operators and then telling a manager class that 'hey, this enum exists -- register it'. Otherwise, you'd only be able to define Operators in your own code - there'd be no extensibility.

编辑:@Helper Method 有一个完美的例子。考虑让其他库定义新的运算符,然后告诉管理器类“嘿,这个枚举存在——注册它”。否则,您只能在自己的代码中定义 Operators - 没有可扩展性。

回答by Tansir1

Since Enums can implement interfaces they can be used for strict enforcing of the singleton pattern. Trying to make a standard class a singleton allows...

由于枚举可以实现接口,因此它们可用于严格执行单例模式。试图使标准类成为单例允许......

  • for the possibility of using reflection techniques to expose private methods as public
  • for inheriting from your singleton and overriding your singleton's methods with something else
  • 使用反射技术将私有方法公开为公共方法的可能性
  • 用于从你的单身人士继承并用其他东西覆盖你的单身人士的方法

Enums as singletons help to prevent these security issues. This might have been one of the contributing reasons to let Enums act as classes and implement interfaces. Just a guess.

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

See https://stackoverflow.com/questions/427902/java-enum-singletonand Singleton class in javafor more discussion.

有关更多讨论,请参阅https://stackoverflow.com/questions/427902/java-enum-singletonJava 中的 Singleton 类

回答by helpermethod

Here's one example (a similar/better one is found in Effective Java 2nd Edition):

这是一个示例(在 Effective Java 2nd Edition 中可以找到类似/更好的示例):

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

Now to get a list of both the Simple + Complex Operators:

现在获取 Simple + Complex Operators 的列表:

List<Operator> operators = new ArrayList<Operator>();

operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));

So here you use an interface to simulate extensible enums (which wouldn't be possible without using an interface).

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

回答by Jorn

The Comparableexample given by several people here is wrong, since Enumalready implements that. You can't even override it.

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

A better example is having an interface that defines, let's say, a data type. You can have an enum to implement the simple types, and have normal classes to implement complicated 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
}

回答by Johan

For example if you have a Logger enum. Then you should have the logger methods such as debug, info, warning and error in the interface. It makes your code loosely coupled.

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

回答by Cosmin Cosmin

Enums are like Java Classes, they can have Constructors, Methods, etc. The only thing that you can't do with them is new EnumName(). The instances are predefined in your enum declaration.

枚举就像 Java 类,它们可以有构造函数、方法等。唯一不能使用它们的是new EnumName(). 实例是在您的枚举声明中预定义的。

回答by sinuhepop

There is a case I often use. I have a IdUtilclass with static methods to work with objects implementing a very simple Identifiableinterface:

有一个案例我经常使用。我有一个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;
    }
}

If I create an Identifiableenum:

如果我创建一个Identifiableenum

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

    }

Then I can get it by its idthis way:

然后我可以通过id这种方式得到它:

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

回答by Anton Bessonov

One of the best use case for me to use enum's with interface is Predicate filters. It's very elegant way to remedy lack of typness of apache collections (If other libraries mayn't be used).

我将枚举与接口一起使用的最佳用例之一是谓词过滤器。这是弥补 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);
    }
}