Reputation: 48837
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.
Upvotes: 7
Views: 196
Reputation: 38255
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
.
Upvotes: 5
Reputation: 55233
As Costi points out, enums themselves can't be generic. However I think I can identify where you went wrong in your design:
There is only one instance of each MyClassX, so I would like to use an enum:
public enum MyEnum { MY_CLASS_1, MY_CLASS_2; }
You're saying that each of these classes is a singleton. So they should in fact each be an enum:
public enum MyClass1 implements MyInterface<SomeOtherClass1> {
INSTANCE;
@Override
public void run(SomeOtherClass1 e) {
// do some stuff with e
}
}
public enum MyClass2 implements MyInterface<SomeOtherClass2> {
INSTANCE;
@Override
public void run(SomeOtherClass2 e) {
// do some stuff with e
}
}
This makes more sense because if you think about it, you don't need to enumerate these two implementations, so there's no need for them to live together. It's enough to use Josh Bloch's enum pattern for each of them individually.
Upvotes: 2