通用处理器的java映射

通用处理器的java映射,java,generics,Java,Generics,在这方面花了相当长的时间后,我想我需要一些帮助。 基本上,我试图创建一组处理器,每个处理器都接受自己类型的对象进行处理。调用类需要能够根据对象的类型获取处理器,并调用该处理器,传递对象。 这就是我所创造的: abstract class Processor<F> { abstract void process(F foo); } class AProcessor extends Processor<Integer> { public void proce

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

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){

    }
}
抽象类处理器{
抽象空洞过程(F-foo);
}
类处理器扩展处理器{
公共void进程(整数foo){
}
}
类BPProcessor扩展处理器{
公共作废流程(长富){
}
}
最初我使用的是处理器接口,这对我来说真的不重要

那么调用类是这样的:

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

}
公共类测试{
私有最终映射>值=新哈希映射>();
公共void main(字符串[]agrs){
测试t=新测试();
t、 value.put(Integer.class,新的处理器());
t、 value.put(Long.class,new BProcessor());
处理器ap=t.get(Integer.class,Processor.class);
}
公共处理器get(类键、类值){
返回value.cast(value.get(key));
}
}
它创建处理器的映射并公开“get”方法。我的问题是,这是无效的,javac抱怨:

Processor<Integer>.class
Processor.class
我最后做了暴力表演:

Processor<T> processor = (Processor<T>)(values.get(key));
处理器处理器=(处理器)(values.get(key)); 但这显然给了我警告。
我怎样才能绕过这个警告呢?我想知道整个方法是否不好,是否有更优雅的方法来设计它。

我不认为有任何方法可以绕过这种未经检查的强制转换的需要,因为内部
映射的类型必须足够广泛,以处理不同的处理器。在这里,您实际上是在执行运行时类型检查,Java泛型是一种只在编译时使用的机制

在这种情况下,强制转换很好:您可以完全控制进入该贴图的对象,因此可以确保它是正确的。如果需要,请使用注释抑制编译器警告


您可能希望处理器接口有一个
类getTargetClass()
,这样您就可以在运行时测试类a处理器适用于什么。这样可以更轻松地对进入地图的处理器进行运行时验证,以确保其正确性。

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

public <T> Processor<T> get(
        Class<T> key, Class<? extends Processor<T>> value) {
//                          ^^^^^^^^^
    return value.cast(values.get(key));
}
因为每个处理器都有一个子类,所以它们可以工作

javac抱怨是因为像
Processor
这样的泛型类型是一个类型,而不是一个类。只有
处理器
是类,因此只有
处理器.class

否则,可以抑制警告:

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

在这种情况下,您可以使用番石榴而不是
Class
,它可以让您拥有
newTypeToken(){}
newTypeToken(){}

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

// 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();
            }
        };
    }
}
输出

Long: 42
Integer: 42
评论

  • 此草案解决方案可以通过消除预先映射类型参数化的任何需要来解决您的问题
  • 它在扩展
    MyProcess
    时使用“匿名”,在工厂扩展
    处理器时使用“匿名”

谢谢,我暂时不发布警告。问题是,我不想知道调用类中每个处理器的特定类:AProcessor.class。只要每个人都知道这些限制,不检查的方法就可以了。(另请参见我的编辑,其中我指出了另一个。)并且,如果您突然得到一个意外的
ClassCastException
,您知道要在检查中包括代码库的哪些部分(放置和获取处理器)。谢谢!这与我的整个方法大不相同,我必须试着看看它如何适合整体设计。我对泛型不太在行,所以需要一段时间才能理解它lol@a7d0rn不客气!我承认这是一个有点不足的文件,因为是,我懒惰:)希望它对你有用。
public <T> Processor<T> get(Class<T> key) {
    @SuppressWarnings("unchecked")
    final Processor<T> p = (Processor<T>) values.get(key);
    return p;
}
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());
// 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();
            }
        };
    }
}
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