sp0*_*00m 7 java generics enums
我有一个参数化的界面:
public interface MyInterface<T> {
void run(T e);
}
Run Code Online (Sandbox Code Playgroud)
和实现接口的类:
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
}
}
Run Code Online (Sandbox Code Playgroud)
不同的MyClass*X*的数量是已知且详尽的,并且每个MyClass*X*只有一个实例,所以我想使用枚举:
public enum MyEnum {
MY_CLASS_1,
MY_CLASS_2;
}
Run Code Online (Sandbox Code Playgroud)
为了能够使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的方法中,当使用Object类型作为e参数时:
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)
}
Run Code Online (Sandbox Code Playgroud)
我认为问题出在这个private MyInterface<?> instance领域:我需要知道实例如何参数化,使用类似的东西private MyInterface<T> instance,但我找不到工作的解决方案......
总之,我被卡住;)
PS:因为run方法体可能很长,我试图避免枚举中的匿名类:
public enum MyEnum {
MY_CLASS_1 {
/* any method, etc. */
},
MY_CLASS_2 {
/* any method, etc. */
},
}
Run Code Online (Sandbox Code Playgroud)
MyEnum 然后变得完全不可读.
这是不可能的.这是我觉得最烦人的枚举限制之一,但你所能做的只是尝试解决它(正如你在5.0之前的Java中所做的那样).
只有枚举本身可以实现接口,并且必须在枚举级别指定泛型,因此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);
}
}
Run Code Online (Sandbox Code Playgroud)
ClassCastException如果您尝试使用MyEnum.MY_CLASS_1.run()除了之外的其他内容,上面的内容将起作用并且您将获得(如预期的那样)SomeOtherClass1.