How are generics managed by enums?

I’ve a parameterized interface:

public interface MyInterface<T> {
    void run(T e);
}

And classes implementing the interface:

public class MyClass1 implements MyInterface<SomeOtherClass1> {
    public void run(SomeOtherClass1 e) {
        // do some stuff with e
    }
}

public class MyClass2 implements MyInterface<SomeOtherClass2> {
    public void run(SomeOtherClass2 e) {
        // do some stuff with e
    }
}

The number of different MyClass*X* is known and exhaustive, and there is only one instance of each MyClass*X*, so I would like to use an enum:

public enum MyEnum {
    MY_CLASS_1,
    MY_CLASS_2;
}

To be able to use MyEnum.MY_CLASS_1.run(someOtherClass1); for example (I would then have every instance of MyInterface in one same place). Is it even possible (and if yes, how)? Because I’m quite stuck for now…


What I tried yet:

public enum MyEnum {

    MY_CLASS_1(new MyClass1()),
    MY_CLASS_2(new MyClass2());

    private MyInterface<?> instance;

    private MyEnum(MyInterface<?> instance) {
        this.instance = instance;
    }

    public void run(/* WhichType? */ e) {
        instance.run(e);
    }

}

In the above method, when using the type Object for the e parameter:

public void run(Object e) {
    instance.run(e);
    //       ^^^
    // The method run(capture#3-of ?) in the type MyInterface<capture#3-of ?> is not applicable for the arguments (Object)
}

The problem I think is with that private MyInterface<?> instance field: I need to know how is the instance parameterized, using something like private MyInterface<T> instance, but I can’t find a working solution…

In short, I’m stuck 😉


PS: since the run methods bodies can be quite long, I’m trying to avoid anonymous classes within the enum:

public enum MyEnum {

    MY_CLASS_1 {
        /* any method, etc. */
    },

    MY_CLASS_2 {
        /* any method, etc. */
    },

}

MyEnum would then become totally unreadable.

Answer

It’s not possible. That’s one of the enum limitations I find most annoying, but all you can do is try to work around it (as you would have done in Java pre-5.0).

Only the enum itself can implement the interface and the generics must be specified at the enum level, so only Object or some common interface for those two would apply in your case.

Declaring any aspect that you want to treat polymorphically (the run() method, in your example) inside the enum itself (and overriding the behavior in each constant) is usually the best workaround. Of course, you need to loosen up your type safety requirements.

If you want to keep those strategies separated, you still need a run(Object) method inside the enum and that will be defined in each constant with some explicit cast, since you simply cannot have different method signatures per enum instance (or even if you can, they won’t be visible as such from the outside).


A hint on how to trick the compiler, if you really want to do that rather than a redesign or explicit casts for each instance:

enum MyEnum implements MyInterface<Object> {
    MY_CLASS_1(new MyClass1()),
    MY_CLASS_2(new MyClass2());

    // you may also drop generics entirely: MyInterface delegate
    // and you won't need that cast in the constructor any more
    private final MyInterface<Object> delegate;

    MyEnum(MyInterface<?> delegate) {
        this.delegate = (MyInterface<Object>) delegate;
    }

    @Override
    public void run(Object e) {
        delegate.run(e);
    }
}

The above will work and you’ll get a ClassCastException (as expected) if you try to use MyEnum.MY_CLASS_1.run() with something other than SomeOtherClass1.

Leave a Reply

Your email address will not be published. Required fields are marked *