我可以在 Java 中创建抽象枚举吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20299074/
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 00:56:13  来源:igfitidea点击:

Can I make an abstract enum in Java?

javaenums

提问by MC Emperor

Below is a valid enum declaration.

下面是一个有效的枚举声明。

public enum SomeEnumClass {

    ONE(1), TWO(2), THREE(3);

    private int someInt;

    public SomeEnumClass(int someInt) {
        this.someInt = someInt;
    }
}

But can I override an abstract class with an enum type?

但是我可以用枚举类型覆盖抽象类吗?

SomeEnumClass.java

SomeEnumClass.java

public abstract enum SomeEnumClass {

    private int someInt;

    public SomeEnumClass(int someInt) {
        this.someInt = someInt;
    }
}

OverridingEnumClass.java

覆盖EnumClass.java

public enum OverridingEnumClass extends SomeEnumClass {

    ONE(1), TWO(2), THREE(3);

}

If not, why not? And what is a good alternative?

如果没有,为什么不呢?什么是好的选择?

采纳答案by chrylis -cautiouslyoptimistic-

No, you can't; enum types all extend Enum, and they're implicitly final. Enums can implement interfaces, or you can declare the relevant methods directly on the enum class in question.

不,你不能;枚举类型都扩展了Enum,并且它们是隐式的final。枚举可以实现接口,也可以直接在有问题的枚举类上声明相关方法。

(I do see the basic idea of what you want, which is a mixin; perhaps the Java 8 interfaces will be a bit more useful in this regard.)

(我确实看到了您想要的基本概念,即 mixin;也许 Java 8 接口在这方面会更有用一些。)

回答by Marcin

If you really need to "extend an enum", you could use the the pre-Java 1.5 Typesafe Enum Pattern (see the bottom of http://www.javacamp.org/designPattern/enum.html) which actually uses a class, not an enum. You lose the ability to use the EnumSet with your "enum"s and you lose some auto-generated methods such as items(), but you get the ability to override methods.

如果您确实需要“扩展枚举”,则可以使用实际使用类的前 Java 1.5 类型安全枚举模式(请参阅http://www.javacamp.org/designPattern/enum.html的底部),不是枚举。您失去了将 EnumSet 与“枚举”一起使用的能力,并且失去了一些自动生成的方法,例如 items(),但您可以覆盖方法。

An example:

一个例子:

// Typesafe enum pattern
public static abstract class Operator {
    public static final Operator ADD = new Operator("+") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam + secondParam;
        }
    };
    public static final Operator SUB = new Operator("-") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam - secondParam;
        }
    };
    public static final Operator MUL = new Operator("*") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam * secondParam;
        }
    };
    public static final Operator DIV = new Operator("/") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam / secondParam;
        }
    };

    private static final Operator[] _ALL_VALUES = {ADD, SUB, MUL, DIV};
    private static final List<Operator> ALL_VALUES = Collections.unmodifiableList(Arrays.asList(_ALL_VALUES));

    private final String operation;

    private Operator(String c) {
        operation = c;
    }

    // Factory method pattern
    public static Operator fromToken(String operation) {
        for (Operator o : Operator.items())
            if (o.operation.equals(operation))
                return o;
        return null;
    }

    public Iterable<Operator> items() {
        return ALL_VALUES;
    }

    public abstract Double apply(Double firstParam, Double secondParam); 

}

回答by rus1f1kat0R

In java you can't extend enum or create some abstract enum or even generify enum. If you want to have some polymorphic extension point over your enum you can apply such a pattern.

在 Java 中,您不能扩展枚举或创建一些抽象枚举,甚至不能泛化枚举。如果你想在你的枚举上有一些多态扩展点,你可以应用这样的模式。

Lets say your enum

让我们说你的枚举

public enum SomeEnumClass {
    ONE, TWO, THREE;
}

And you want to have some behavior associated with each value. But you don't want to hardcode each, but rather want to have ability to supply any other. So you should declare interface

并且您希望有一些与每个值相关联的行为。但是您不想对每个都进行硬编码,而是希望能够提供任何其他内容。所以你应该声明接口

public interface SomeEnumVisitor<P, R> {
     R one(P param);
     R two(P param);
     R three(P param);
}

Then add abstract method to enum declaration and implementation of this method for each value

然后将抽象方法添加到枚举声明和每个值的此方法的实现

public enum SomeEnumClass {
    ONE {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.one(param);
        }
    }, TWO {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.two(param);
        }
    }, THREE {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.three(param);
        }
    };
    public abstract <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param);
}

So that you can create visitor implementation for extending your enum behavior. For example in your case you wanted to associate Integer value with each enum value.

这样您就可以创建访问者实现来扩展您的枚举行为。例如,在您的情况下,您希望将 Integer 值与每个枚举值相关联。

public class IntValueVisitor implements SomeClassVisitor<Integer, Void> {
     @Override
     public Integer one(Void param){
         return 1;
     }

     @Override
     public Integer two(Void param){
         return 2;
     }

     @Override
     public Integer three(Void param){
         return 3;
     }    
}

And finally use this visitor where you need

最后在你需要的地方使用这个访问者

SomeClassEnum something = getAnyValue();
// this expression will return your particular int value associated with particular enum.
int intValue = something.accept(new IntValueVisitor(), null);

Of course this pattern applicable if it is not appropriate to have everything declared inside enum, for example if you have enum declaration in library and want to extend enum's behavior in the main application. Or you just don't want to couple enum definition and implementation details.

当然,如果不适合在 enum 中声明所有内容,则此模式适用,例如,如果您在库中有 enum 声明并希望在主应用程序中扩展 enum 的行为。或者您只是不想将枚举定义和实现细节结合起来。

In order to simplify this pattern implementation there is a library that can generate enum and visitor based on annotationso that all you need to declare in your code is

为了简化这个模式的实现,有一个库可以根据注解生成枚举和访问者,所以你需要在代码中声明的是

@AutoEnum(value = {"one", "two", "three"}, name = "SomeEnumClass")
public interface SomeEnumMarker {}

The tool will do rest for you.

该工具将为您做休息。