1

I have an abstract class (or an interface). In this class I want to define an enum, in order to force classes that extend this abstract class (or implement this interface) to declare an enum with the same name.

abstract class Operator {
    public abstract enum Symbol;
    public Symbol value;
}

class Binary extends Operator {
    public enum Symbol {
        pls,
        min,
        mul,
        div,
        //...
    }
}
class Unary extends Operator {
    public enum Symbol {
        sin,
        cos,
        tan,
        cot,
        //...
    }
}

Assume I can't know the values of sub classes enums. I want that every extending class had an enum with that name and its values. I want to use enums (especially because it's easy to switch enums)

barsdeveloper
  • 930
  • 8
  • 28
  • There is a way to allow "user-specified" enums, but it will take a moment for me to type up – Rogue May 01 '14 at 21:07
  • this idea makes absolutely no logical sense and shows a fundamental misunderstand / lack of comprehension of the reason the enum construct exists –  May 01 '14 at 21:09
  • I hesitate to open this can of worms, but generics could do this. – chrylis -cautiouslyoptimistic- May 01 '14 at 21:11
  • `enum` is automatically `final` can't subclass it –  May 01 '14 at 21:19
  • possible duplicate of [add values to enum](http://stackoverflow.com/questions/55375/add-values-to-enum) –  May 01 '14 at 21:28
  • @JarrodRoberson I wouldn't way these two are exact duplicates: OP doesn't want to extend the base enum; he wants to force subclasses of the enclosing class to define an enum with the same name (which anyway has no use) – Raffaele May 02 '14 at 08:54
  • you would have to `extend` the `abstract` Symbol enum, they are the same question in spirit if not in content. –  May 02 '14 at 16:19

3 Answers3

3

There's no way to do this thing and moreover, even if it were, how would you call the subclass' implementation? I mean, only method calls can be virtual, ie dispatched at runtime. Types can not, so without cheating with reflection (which throws away any type safety anyhow, so that you don't even need to subclass), you would not be able to call the overridden type (in fact, types can't be overridden).

Maybe you can still achive your objectives by using composition:

public abstract class Operator<T extends Enum<T>> {
  public final Class<T> symbol;
  public Operator(Class<T> symbol) { this.symbol = symbol; }
}

public enum BinarySymbol { PLS, MIN, MUL, DIV }

public class Binary extends Operator<BinarySymbol> {
  public Binary(Object operand1, Object operand2, BinarySymbol symbol) {
    super(symbol);
  }
}

Your base class Operator can dynamically read the enumerated values through reflection, via Class.getEnumConstants()

Raffaele
  • 20,627
  • 6
  • 47
  • 86
-1

You can't enforce it at compile time. One way would be to use reflection at runtime to see if the class has been implemented correctly. I don't suggest this, but it's possible.

Rob Eden
  • 362
  • 2
  • 7
-1

What you can do is have enums that implement a common interface, and then utilize those interfaces:

public interface YourEnumInterface<E extends Enum<E> & YourEnumInterface<E>> {

    //methods that your enum should be implementing

}

The extension for the interface generic declaration is there to guarantee it is only called by enums that implement your interface

And then any enum you have to specify can implement it like so:

public enum MyEnum implements YourEnumInterface<MyEnum> {

    // enum constants
    TEST_VALUE;

    // implementation of interface methods

}

From there, you would simply work with the YourEnumInterface as an object, and you can pass enum values for them:

public void doSomething(YourEnumInterface enm) {
    //work with enm
}

//Elsewheres...
doSomething(MyEnum.TEST_VALUE);

It should be noted, that once you lower your enum down to the interface itself, you won't be able to change the constant you are working with (without casting, which can potentially be unsafe). This should really be used more or less for passing things to a destination that just works with the values (like a config enum, or internalization of strings, etc)

So in relevance to forcing a subclass to implement it:

public class YourSuperClass {
    public abstract YourEnumInterface symbol;
}

A runnable example

public class EnumMagic {

    public static void main(String[] args) {
        YourSubClass clazz = new YourSubClass();
        //prints the default value
        System.out.println(clazz.getEnum().getValue());
        //gets the value of a specified enum constant
        System.out.println(clazz.getEnum().SECOND_TEST.getValue());
    }

}

abstract class YourSuperClass {

    protected YourEnumInterface symbol;

    public abstract YourEnumInterface getEnum();

}

interface YourEnumInterface<E extends Enum<E> & YourEnumInterface<E>> {

    public int getValue();

}

class YourSubClass extends YourSuperClass {

    public enum MyEnum implements YourEnumInterface<MyEnum> {

        TEST_VALUE(1),
        SECOND_TEST(2);

        private final int val;

        private MyEnum(int example) {
            this.val = example;
        }

        public int getValue() {
            return this.val;
        }

    }

    public YourSubClass() {
        this.symbol = MyEnum.TEST_VALUE;
    }

    public MyEnum getEnum() {
        return MyEnum.TEST_VALUE;
    }

}

The output of this progam is:

1
2

And you can simply get the class' specified enum constant via getEnum, which they will return their own internal enum.

However, once downcasted to the super type, e.g. YourSuperClass intc = clazz;, then you will lose this ability to specify the enum itself. Depending on how you store your instances will determine whether or not this requires changes.

Rogue
  • 11,105
  • 5
  • 45
  • 71
  • this has nothing to do with the question about instances of the `enum` being different between implementations –  May 01 '14 at 21:18
  • Except it does, you can have multiple enums implement the same interface and then use them interchangeably... – Rogue May 01 '14 at 21:19
  • Read the question for comprehension slowly, they want an `enum` with no values, then they want to specify the values with a specific implementation that has nothing to do with methods or anything else you are on about here. Symbol.PLUS is a instance of Symbol Symbol.SIN is an instance of Symbol. Your attempt at an answer doesn't allow this at all on the same type because it can't. –  May 01 '14 at 21:21
  • As the OP states: "In this class I want to define an enum, in order to force classes that extend this abstract class (or implement this interface) to declare an enum with the same name." *That is exactly how you accomplish this*. You can't do it in the way you specified, which I clarified, but I offered a solution which works – Rogue May 01 '14 at 21:22
  • They also want to be able to get to the value instances of Symbol, an Interface **is not an enum** it can't have values! They want the type to have the values that are accessible. Read again for comprehension of the problem. Show some code that does what I am explaining that compiles and runs and I will upvote this answer, as it is stands it isn't a functional answer to the question. –  May 01 '14 at 21:24
  • This is already compilable code, I'll update the answer even further. – Rogue May 01 '14 at 21:25
  • It doesn't do what the example code is asking to do, mainly because [you can't do what they are asking in Java.](http://stackoverflow.com/questions/55375/add-values-to-enum) –  May 01 '14 at 21:27