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

}