Can I make an abstract enum in Java?
Solution 1:
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.
(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.)
Solution 2:
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.
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.
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.
In order to simplify this pattern implementation there is a library that can generate enum and visitor based on annotation so 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.
Solution 3:
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.
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);
}