如何通过枚举管理generics?
我有一个参数化的界面:
public interface MyInterface { void run(T e); }
和实现接口的类:
public class MyClass1 implements MyInterface { public void run(SomeOtherClass1 e) { // do some stuff with e } } public class MyClass2 implements MyInterface { 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); } }
在上面的方法中,当使用类型Object作为e
参数时:
public void run(Object e) { instance.run(e); // ^^^ // The method run(capture#3-of ?) in the type MyInterface is not applicable for the arguments (Object) }
我认为问题在于private MyInterface instance
字段:我需要知道如何使用private MyInterface instance
等参数化private MyInterface instance
,但我找不到工作解决方案……
简而言之,我被卡住;)
PS:因为run
方法体可能很长,所以我试图避免枚举中的匿名类:
public enum MyEnum { MY_CLASS_1 { /* any method, etc. */ }, MY_CLASS_2 { /* any method, etc. */ }, }
然后MyEnum
变得完全不可读。
这是不可能的。 这是我觉得最烦人的枚举限制之一,但你所能做的就是尝试解决它(正如你在5.0之前的Java中所做的那样)。
只有枚举本身可以实现接口,并且必须在枚举级别指定generics,因此在您的情况下,只有Object
或这两者的一些通用接口才适用。
在枚举本身内声明要多态处理的任何方面run()
在示例中为run()
方法)(并覆盖每个常量中的行为)通常是最佳解决方法。 当然,您需要放松您的类型安全要求。
如果你想保持这些策略是分开的,你仍然需要在枚举中使用run(Object)
方法,并且在每个常量中使用一些显式强制转换定义,因为你根本不能为每个枚举实例提供不同的方法签名(或者即使你可以,他们不会从外面看到它们。
提示如何欺骗编译器,如果你真的想这样做而不是为每个实例重新设计或显式转换:
enum MyEnum implements MyInterface
如果您尝试将MyEnum.MY_CLASS_1.run()
与SomeOtherClass1
以外的其他内容一起使用,则上述方法将起作用并且您将获得ClassCastException
(如预期的那样)。
正如科斯蒂指出的那样 ,枚举本身不是通用的 。 但是我想我可以确定你的设计出错了:
每个MyClass X只有一个实例,所以我想使用枚举:
public enum MyEnum { MY_CLASS_1, MY_CLASS_2; }
你说每个类都是单例。 所以他们实际上每个都应该是一个枚举:
public enum MyClass1 implements MyInterface { INSTANCE; @Override public void run(SomeOtherClass1 e) { // do some stuff with e } } public enum MyClass2 implements MyInterface { INSTANCE; @Override public void run(SomeOtherClass2 e) { // do some stuff with e } }
这更有意义,因为如果你考虑它,你不需要枚举这两个实现,所以它们不需要一起生活。 只需单独使用Josh Bloch的enum模式就足够了。