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

时间:2013-11-30 10:22:40

标签: java enums

以下是有效的枚举声明。

public enum SomeEnumClass {

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

    private int someInt;

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

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

SomeEnumClass.java

public abstract enum SomeEnumClass {

    private int someInt;

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

OverridingEnumClass.java

public enum OverridingEnumClass extends SomeEnumClass {

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

}

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

3 个答案:

答案 0 :(得分:34)

不,你不能;枚举类型全部扩展为Enum,它们隐式final。枚举可以实现接口,或者您可以直接在相关的枚举类中声明相关方法。

(我确实看到了你想要的基本概念,这是一个混合;也许Java 8接口在这方面会更有用。)

答案 1 :(得分:8)

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

让我们说你的枚举

public enum SomeEnumClass {
    ONE, TWO, THREE;
}

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

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

然后为每个值

添加抽象方法以枚举声明和实现此方法
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);
}

这样您就可以创建访问者实现以扩展您的枚举行为。例如,在您的情况下,您希望将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;
     }    
}

最后在您需要的地方使用此访问者

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

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

为了简化此模式实现there is a library that can generate enum and visitor based on annotation,以便您需要在代码中声明所有内容

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

该工具将为您休息。

答案 2 :(得分:4)

如果你真的需要“扩展枚举”,你可以使用pre-Java 1.5 Typesafe Enum Pattern(参见http://www.javacamp.org/designPattern/enum.html的底部),它实际上使用的是类,而不是枚举。您失去了使用EnumSet和“枚举”的能力,并且您丢失了一些自动生成的方法,例如items(),但您可以覆盖方法。

一个例子:

// 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); 

}