Sam McCreery
Sam McCreery

Reputation: 552

Subclassing an enum value

I want to be able to subclass some values in an enum, in order that I don't have to repeat code too much. Is there some way I can do this? Here's an example of what I want to achieve, which Eclipse quickly tells me is an abomination:

public enum Foo {
    BAR {
        @Override
        public void taskA() {
            System.out.println("A");
        }

        @Override
        public void taskB() {}
    },
    BAZ extends BAR {
        @Override
        public void taskB() {
            System.out.println("B");
        }
    };

    public abstract void taskA();
    public abstract void taskB();
}

BAR would have only the implementation of taskA and an empty taskB, and BAZ would have both methods - BAR's implementation of taskA, and its own implementation of taskB.

I'm not changing the values of the enum after it's declared, so why doesn't this work? I could call BAR's taskA method within BAZ, so why can't I do this?

Upvotes: 2

Views: 419

Answers (2)

slartidan
slartidan

Reputation: 21608

Enum-Constants are objects (instances), not classes. You can only subclass classes.

However even that will not work: you can only extend enums with anynomous inner classes.

You will have to find another solution for your use case. You could:

  • use a static method for the shared code
  • call BAR.taskA() in BAZ
  • make taskA not abstract and put your code there
  • use normal constants, instead of enums

But my favorit is:

  • inject behaviour instead of overriding!

Example code:

class Behavior {
    public static Runnable A = new Runnable() {
        public void run() {
            System.out.println("A");
        }
    }

    public static Runnable B = new Runnable() {
        public void run() {
            System.out.println("B");
        }
    }

    public static Runnable DO_NOTHING = new Runnable() {
        public void run() {
        }
    }
}

public enum Foo {
    BAR(Behavior.A, Behavior.DO_NOTHING),
    BAZ(Behavior.A, Behavior.B);

    private final Runnable mechanismA;
    private final Runnable mechanismB;

    private Foo(Runnable mechanismA, Runnable mechanismB) {
        this.mechanismA = mechanismA;
        this.mechanismB = mechanismB;
    }

    public void taskA() {
        mechanismA.run;
    }

    public void taskB() {
        mechanismB.run;
    }
}

Pros of this solution:

  • The code explicitly defines the behavior of each enum constant - no implicit calculations => easier to read
  • You can use inheritance, etc in the Behavior-class
  • You can easily switch behaviorA and behaviorB - or reuse that code anywhere else

If you have Java8 available you can even shorten the code to this:

public static Runnable A = () -> {
    System.out.println("A");
};

Upvotes: 2

scottb
scottb

Reputation: 10084

I want to be able to subclass some values in an enum, in order that I don't have to repeat code too much.

The usual way to share code among constant-specific methods is to declare a private static method (either in the enum itself or in a utility helper class) which contains the common code that you wish to access from your constant-specific methods.

For example ...

public enum Foo {
    BAR {
        @Override
        public void taskA() {
            commonToTaskAandB();
            System.out.println("B"); 
       }

        @Override
        public void taskB() {}
    },
    BAZ {
        @Override
        public void taskB() {
            commonToTaskAandB();
            System.out.println("B");
        }
    };

    public abstract void taskA();
    public abstract void taskB();

    private static void commonToTaskAandB() {
        // shared code here
        :
        :
    }

}

Note that the code "BAZ extends Bar" is illegal because BAZ is not a type. BAZ is an instance of your Enum<Foo> type. An instance cannot extend another type. It is incorrect to apply object-oriented principles like inheritance to enum constants because, in Java, enum constants are instances of a class and not classes themselves.

Upvotes: 2

Related Questions