Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make an abstract enum in Java?

Tags:

java

enums

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

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

}

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

like image 736
MC Emperor Avatar asked Nov 30 '13 10:11

MC Emperor


People also ask

Is enum abstract data type?

All enum types implicitly extend the Enum abstract class. An enum type cannot be instantiated directly. Internally, each enum value contains an integer, corresponding to the order in which they are declared in the source code, starting from 0.

Can an enum be extended Java?

No, we cannot extend an enum in Java. Java enums can extend java. lang. Enum class implicitly, so enum types cannot extend another class.

Can enum be inherited?

Enums cannot inherit from other enums. In fact all enums must actually inherit from System.

Can you make a interface for an enum?

Yes, Enum implements an interface in Java, it can be useful when we need to implement some business logic that is tightly coupled with a discriminatory property of a given object or class.


3 Answers

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

like image 128
chrylis -cautiouslyoptimistic- Avatar answered Oct 19 '22 08:10

chrylis -cautiouslyoptimistic-


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.

like image 39
rus1f1kat0R Avatar answered Oct 19 '22 06:10

rus1f1kat0R


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

}
like image 6
Marcin Avatar answered Oct 19 '22 07:10

Marcin