我有一个参数化界面:
public interface MyInterface<T> {
void run(T e);
}
实现界面的类:
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
}
}
不同的MyClass * X *的数量是已知且详尽的,并且每个MyClass * X *只有一个实例,所以我想使用枚举:
public enum MyEnum {
MY_CLASS_1,
MY_CLASS_2;
}
例如,为了能够使用MyEnum.MY_CLASS_1.run(someOtherClass1);
(我会将MyInterface的每个实例放在同一个地方)。甚至可能(如果是的话,如何)?因为我现在非常困难......
我尝试了什么:
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);
}
}
在上面的方法中,当使用e
参数的类型Object时:
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)
}
我认为问题在于private MyInterface<?> instance
字段:我需要知道如何使用类似private MyInterface<T> instance
的参数来设置实例,但我无法找到可行的解决方案......
简而言之,我被卡住了;)
PS:由于run
方法体可能很长,我试图避免枚举中的匿名类:
public enum MyEnum {
MY_CLASS_1 {
/* any method, etc. */
},
MY_CLASS_2 {
/* any method, etc. */
},
}
MyEnum
将变得完全不可读。
答案 0 :(得分:5)
这是不可能的。这是我觉得最烦人的枚举限制之一,但你所能做的只是尝试解决它(正如你在5.0之前的Java中所做的那样)。
只有enum本身可以实现接口,并且必须在枚举级别指定泛型,因此只有Object
或这两者的一些通用接口才适用于您的情况。
在枚举本身内声明要以多态方式处理的任何方面(在您的示例中为run()
方法)(并覆盖每个常量中的行为)通常是最佳解决方法。当然,您需要放松您的类型安全要求。
如果你想将这些策略分开,你仍然需要在枚举中使用run(Object)
方法,并且将在每个常量中使用一些显式强制转换定义,因为每个枚举实例根本不能有不同的方法签名(或者即使你可以,也不会从外面看到它们。
提示如何欺骗编译器,如果你真的想要这样做而不是为每个实例重新设计或显式转换:
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);
}
}
如果您尝试将ClassCastException
与MyEnum.MY_CLASS_1.run()
以外的其他内容一起使用,则上述操作会有效SomeOtherClass1
(按预期方式)。
答案 1 :(得分:2)
作为Costi points out,枚举自己can't be generic。但是我想我可以确定你的设计出了什么问题:
每个MyClass X 只有一个实例,所以我想使用 一个枚举:
public enum MyEnum { MY_CLASS_1, MY_CLASS_2; }
你说这些课程都是单身。所以他们实际上应该每个一个枚举:
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
}
}
这更有意义,因为如果你考虑一下,你不需要枚举这两个实现,所以它们不需要一起生活。对每个人单独使用Josh Bloch's enum pattern就足够了。