通用处理器的java地图

时间:2015-05-07 13:56:00

标签: java generics

花了相当长的时间后,我想我可以使用一些帮助。 基本上我试图创建一组处理器,每个处理器都接受自己要处理的对象类型。调用类需要能够根据对象的类型获取处理器并调用该处理器,并传递该对象。 这就是我创造的:

abstract class Processor<F> {
    abstract void process(F foo);
}

class AProcessor extends Processor<Integer> {
    public void process(Integer foo){

    }
}

class BProcessor extends Processor<Long> {
    public void process(Long foo){

    }
}

最初我使用处理器接口,它对我来说并不重要。

然后调用类就是这样:

public class Test {

    private final Map<Class<?>, Processor<?>> values = new HashMap<Class<?>, Processor<?>>();

    public void main(String[] agrs){
        Test t = new Test();
        t.values.put(Integer.class, new AProcessor());
        t.values.put(Long.class, new BProcessor());

        AProcessor ap = t.get(Integer.class, Processor<Integer>.class);

    }

    public <T> Processor<T> get( Class<T> key, Class<Processor<T>> value ) {
        return value.cast(values.get(key));
    }

}

它会创建一个处理器地图并公开&#39; get&#39;方法。我遇到的问题是这是无效的,javac抱怨:

Processor<Integer>.class

我最后做了蛮力演员:

Processor<T> processor = (Processor<T>)(values.get(key));

但它显然给了我未经检查的投射警告。 我怎么能绕过这个警告?我想知道整个方法是不是很好,并且有更优雅的方式来设计它。

3 个答案:

答案 0 :(得分:4)

在您的情况下,您可以将其更改为:

public <T> Processor<T> get(
        Class<T> key, Class<? extends Processor<T>> value) {
//                          ^^^^^^^^^
    return value.cast(values.get(key));
}

让你这样做:

Processor<Integer> ap = t.get(Integer.class, AProcessor.class);

或者:

public <T, P extends Processor<T>> P get(
//         ^^^^^^^^^^^^^^^^^^^^^^
        Class<T> key, Class<P> value) {
    return value.cast(values.get(key));
}

让你这样做:

AProcessor ap = t.get(Integer.class, AProcessor.class);

这些工作是因为每个处理器都有一个子类。

javac抱怨,因为像Processor<Integer>这样的通用类型是类型而不是。只有Processor,因此只有Processor.class

否则,您可以禁止警告:

public <T> Processor<T> get(Class<T> key) {
    @SuppressWarnings("unchecked")
    final Processor<T> p = (Processor<T>) values.get(key);
    return p;
}

这种未经检查的演员设计在大多数情况下都很好,但它会因泛型类型而分解。如果您有例如一个Processor<List<String>>,您只能将其检索为Processor<List>。这是因为List.class只有Class<List>

换句话说,假设有一个:

class CProcessor extends Processor<List<String>> {
    public void process(List<String> foo) {}
}
t.values.put(List.class, new CProcessor());
// oops, we lost the type of the List
Processor<List> c1 = t.get(List.class);
// and this doesn't compile
Processor<List<String>> c2 = t.get(List.class);

然后假设有一个:

class DProcessor extends Processor<List<Float>> {
    public void process(List<Float> foo) {}
}
// oops, we just replaced CProcessor
t.values.put(List.class, new DProcessor());

在这种情况下,你可以使用像番石榴TypeToken而不是Class这样的东西,它可以让你拥有new TypeToken<List<String>>() {}new TypeToken<List<Float>>() {}

答案 1 :(得分:2)

我认为有一种方法可以解决这种情况下未经检查的强制转换的需要,因为内部Map的类型必须足够广泛才能处理不同的处理器。您实际上在这里进行运行时类型检查,Java泛型是一种仅编译时的机制。

在这种情况下,演员阵容很好:您可以完全控制进入该地图的对象,因此您可以确保它是正确的。如果需要,请使用注释来禁止编译器警告。

您可能希望处理器接口具有Class<T> getTargetClass(),以便您可以在运行时测试处理器适用的类。这样可以更容易地对进入地图的处理器进行运行时验证,以确保它们是正确的。

答案 2 :(得分:0)

以下是我认为您通过匿名和半功能代码尝试实现的示例:

// simple parametrized functional interface
interface Processor<T extends Number> {
    void process();
}
// definition of the actual process - "MyProcess" to avoid name clashes
abstract class MyProcess<T> implements Runnable {

    protected T t;
    MyProcess(T t) {
        this.t= t;
    }
}
// factory class to get Processor instances
class ProcessorFactory {
    static <T extends Number>Processor<?> getProcessor(final MyProcess<T> process) {
        return new Processor<T>() {
            @Override
            public void process() {
                process.run();
            }
        };
    }
}

然后,在main方法某处...

ProcessorFactory.getProcessor(new MyProcess<Long>(42l) {
    @Override
    public void run() {
        System.out.printf("%s: %d%n", t.getClass().getSimpleName(), t);
    }
})
.process();
ProcessorFactory.getProcessor(new MyProcess<Integer>(42) {
    @Override
    public void run() {
        System.out.printf("%s: %d%n", t.getClass().getSimpleName(), t);
    }
})
.process();

<强>输出

Long: 42
Integer: 42

<强>评论

  • 此草案解决方案可以通过删除任何预先映射您的类型参数化的需要来解决您的问题
  • 在扩展MyProcess的同时使用“匿名化”,并且在工厂中扩展Processor时更具争议性。