如何通过枚举管理泛型?

时间:2014-01-07 13:44:30

标签: java generics enums

我有一个参数化界面:

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将变得完全不可读。

2 个答案:

答案 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);
    }
}

如果您尝试将ClassCastExceptionMyEnum.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就足够了。