枚举如何管理泛型? [英] How are generics managed by enums?

查看:121
本文介绍了枚举如何管理泛型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我有一个参数化界面:

  public界面MyInterface< T> {
void run(T e);
}

实现界面的类:

  public class MyClass1实现MyInterface< SomeOtherClass1> {
public void run(SomeOtherClass1 e){
//做一些东西与e
}
}

public class MyClass2实现MyInterface< SomeOtherClass2> {
public void run(SomeOtherClass2 e){
//使用e



不同的MyClass * X *的数量是已知和详尽的,每个MyClass * X *只有一个实例,所以我想使用一个枚举: p>

  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 MyClass2());

private MyInterface<?>实例;

private MyEnum(MyInterface<?> instance){
this.instance = instance;
}

public void run(/ * WhichType?* / e){
instance.run(e);
}

}

在上述方法中, e 参数的对象类型:

  public void run(Object e){
instance.run(e);
// ^^^
//类型为MyInterface< capture#3-of?>中的方法run(capture#3-of?)不适用于参数(Object)
}

我认为是这样的问题 private MyInterface<?>实例字段:我需要知道实例是如何参数化的,使用类似于 private MyInterface< T>实例,但是找不到工作解决方案...



简而言之,我被卡住了) b
$ b




PS:由于运行方法体可能相当长,我正在尝试以避免枚举中的匿名类:

  public enum MyEnum {

MY_CLASS_1 {
/ *任何方法等* /
},

MY_CLASS_2 {
/ *任何方法等* /
} ,

}

MyEnum 将变得完全不可读。

解决方案

这是不可能的。这是我发现最令人厌烦的枚举限制之一,但您可以做的只是尝试解决它(就像您在5.0之前的Java中所做的那样)。



只有枚举本身可以实现接口,并且必须在枚举级别指定泛型,所以只有 Object 或者这些通用接口适用于你的情况。 p>

在枚举本身内部声明您想要多态的任何方面(您的示例中的 run()方法) (并覆盖每个常量中的行为)通常是最好的解决方法。当然,你需要松开你的类型安全要求。



如果你想保持这些策略分开,你仍然需要一个 run )方法在枚举中,并且将在每个常量中定义一些明确的转换,因为您根本不能在每个枚举实例中拥有不同的方法签名(或者即使可以,也不会显示为如果你真的想要这样做,而不是这样做,那么这个提示就是从外面来的。






对每个实例进行重新设计或显式转换:

 枚举MyEnum实现MyInterface< Object> {
MY_CLASS_1(new MyClass1()),
MY_CLASS_2(new MyClass2());

//你也可以完全丢弃泛型:MyInterface委托
//并且你不需要在构造函数中再次执行
private final MyInterface< Object>代表;

MyEnum(MyInterface<?> delegate){
this.delegate =(MyInterface< Object>)delegate;
}

@Override
public void run(Object e){
delegate.run(e);
}
}

上面的工作,你会得到一个 ClassCastException (如预期),如果您尝试使用 MyEnum.MY_CLASS_1.run() SomeOtherClass1


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.

解决方案

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.

这篇关于枚举如何管理泛型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆