为什么Enum会实现接口?

unj*_*nj2 180 java enums

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

hel*_*hod 254

这是一个例子(在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 :-/
}
Run Code Online (Sandbox Code Playgroud)

现在获取Simple + Complex运算符的列表:

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

operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));
Run Code Online (Sandbox Code Playgroud)

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

  • 复杂的运营商可能是"战俘"等. (3认同)
  • 第一次看到 Enum 语法(成员后面有大括号),我已经使用 Java 编程 6 年了。直到。 (3认同)

Bri*_*new 125

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


Jor*_*orn 22

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

一个更好的例子是拥有一个定义数据类型的接口.您可以使用枚举来实现简单类型,并使用普通类来实现复杂类型:

interface DataType {
  // methods here
}

enum SimpleDataType implements DataType {
  INTEGER, STRING;

  // implement methods
}

class IdentifierDataType implements DataType {
  // implement interface and maybe add more specific methods
}
Run Code Online (Sandbox Code Playgroud)

  • 是的.很奇怪!枚举已经实现了Comparable接口,并且不允许覆盖.我查找了枚举类的java源代码,无法找到compareTo实现.谁能告诉我什么在compareTo方法和ENUM中进行比较? (2认同)
  • @AKh它比较了序数,这意味着自然顺序是枚举常量在源文件中的顺序. (2认同)

sin*_*pop 14

我经常使用一个案例.我有一个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我创建一个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;
        }

    }
Run Code Online (Sandbox Code Playgroud)

然后我可以这样得到它id:

MyEnum e = IdUtil.get(MyEnum.class, 1);
Run Code Online (Sandbox Code Playgroud)


Tan*_*ir1 13

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

  • 有可能使用反射技术将私有方法公开为public
  • 继承你的单身人士并用其他东西覆盖你的单身人士的方法

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

有关更多讨论,请参阅java中的/sf/ask/29953171/Singleton类.


Chr*_*ett 10

它是可扩展性所必需的 - 如果有人使用您开发的API,您定义的枚举是静态的; 它们无法添加或修改.但是,如果您让它实现一个接口,那么使用API​​的人可以使用相同的接口开发自己的枚举.然后,您可以使用枚举管理器注册此枚举,该管理器将枚举与标准接口集合在一起.

编辑:@Helper Method就是一个很好的例子.考虑让其他库定义新的运算符,然后告诉管理器类'嘿,这个枚举存在 - 注册它'.否则,您只能在自己的代码中定义操作符 - 没有可扩展性.


Tof*_*eer 7

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

我无法想到枚举不应该能够实现接口的原因,同时我也无法想到它们的合理理由.

我会说,一旦你开始在枚举中添加类似接口或方法之类的东西,你应该考虑让它成为一个类.当然我确信有非传统枚举的有效案例,并且由于限制是一个人为的限制,我赞成让人们做他们想要的事情.

  • 这是因为枚举都扩展了java.lang.Enum,Java类只能从一个类扩展. (5认同)
  • "...所以在大多数情况下,你可以使用枚举来完成一个类,但我不能说我的枚举继承自抽象类.所以是的,强调"大部分". (4认同)

Joh*_*han 6

例如,如果您有一个Logger枚举.然后你应该在界面中使用logger方法,如debug,info,warning和error.它使您的代码松散耦合.


hus*_*ayt 6

最常见的用法是将两个枚举的值合并为一个组并对其进行类似处理.例如,了解如何加入Fruits和Vegatables.


Rob*_*kal 6

上面提到策略的帖子并没有足够强调使用枚举的策略模式的轻量级实现可以为您带来什么:

public enum Strategy {

  A {
    @Override
    void execute() {
      System.out.print("Executing strategy A");
    }
  },

  B {
    @Override
    void execute() {
      System.out.print("Executing strategy B");
    }
  };

  abstract void execute();
}
Run Code Online (Sandbox Code Playgroud)

您可以将所有策略放在一个地方,而不需要为每个策略单独的编译单元。您只需使用以下命令即可获得不错的动态调度:

Strategy.valueOf("A").execute();
Run Code Online (Sandbox Code Playgroud)

使 java 读起来几乎像一门不错的松散类型语言!


Ant*_*nov 5

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


mar*_*rea 5

在 jar 文件中创建常量时,让用户扩展枚举值通常很有帮助。我们使用枚举作为 PropertyFile 键并陷入困境,因为没有人可以添加任何新的!下面的效果会好得多。

鉴于:

public interface Color {
  String fetchName();
}
Run Code Online (Sandbox Code Playgroud)

和:

public class MarkTest {

  public static void main(String[] args) {
    MarkTest.showColor(Colors.BLUE);
    MarkTest.showColor(MyColors.BROWN);
  }

  private static void showColor(Color c) {
    System.out.println(c.fetchName());
  }
}
Run Code Online (Sandbox Code Playgroud)

罐子里可以有一个枚举:

public enum Colors implements Color {
  BLUE, RED, GREEN;
  @Override
  public String fetchName() {
    return this.name();
  }
}
Run Code Online (Sandbox Code Playgroud)

用户可以扩展它以添加自己的颜色:

public enum MyColors implements Color {
  BROWN, GREEN, YELLOW;
  @Override
  public String fetchName() {
    return this.name();
  }
}
Run Code Online (Sandbox Code Playgroud)