Java泛型:捕获无法应用于Object

时间:2011-11-29 13:07:15

标签: java generics

我的代码有Map个(消息)处理程序。我正在尝试使处理程序变得一致(如界面处理程序所示)。如果没有泛型,处理程序都需要从Object转换到相应的类,这将是很好的避免(但一切正常)。对于每个消息类(下面的Foo),我有一个处理程序类。

如何将任何类型的Map映射到任何类型的处理程序,并使用“只”Object来获取/调用? (无法限制handleMessage(Object)的参数)

见下面的MWE。

import java.util.*;
public class Logic
{   
    Map<Class<?>, Handler<?>> handlers = new HashMap<Class<?>, Handler<?>>();

    public void run()
    {   
        handlers.put(Foo.class, new FooHandler());
    }   

    public void handleMessage(Object msg)
    {   
        Handler<?> handler = handlers.get(msg.getClass());
        if (handler != null) {
            handler.execute(msg);
        }   
    }   

    private interface Handler<T>
    {   
        public void execute(T msg);
    }   

    private class FooHandler implements Handler<Foo>
    {   
        public void execute(Foo msg) {}
    }   

    private class Foo {}
}

此代码生成:

  逻辑.java:16:在Logic.Handler中执行(捕获#x of?)无法应用&gt; to(java.lang.Object)               handler.execute(MSG);

如何在保持Handler接口通用的同时修复它?

3 个答案:

答案 0 :(得分:7)

您无法在字段中定义键和值之间的关系,但只要使用这些方法访问地图,您就可以使用访问器方法来强制执行它。

private final Map<Class, Handler> handlers = new HashMap<Class, Handler>();

public <T> void addHandler(Class<T> clazz, Handler<T> handler) {
    handlers.put(clazz, handler);
}

@SuppressWarnings("unchecked")
public <T> Handler<T> getHandler(Class<T> clazz) {
    return (Handler<T>) handlers.get(clazz);
}

@SuppressWarnings("unchecked")
public <T> Handler<T> getHandlerFor(T t) {
    return getHandler((Class<T>) t.getClass());
}

public void run()    {
    addHandler(Foo.class, new FooHandler());
}

public <T> void handleMessage(T msg) {
    Handler<T> handler = getHandlerFor(msg);
    if (handler != null) {
        handler.execute(msg);
    }
}

答案 1 :(得分:2)

问题是execute()采用某种参数类型,比Object更具体。

但是,在handleMessage()方法中,编译器不知道参数的类型。假设FooHandler为类Bar注册的情况(这是可能的)。

在该上下文handler.execute(msg);实际上会导致使用FooHandler#execute(Foo)参数调用Bar,这将导致ClassCastException(除非Bar extends Foo)。因此编译器拒绝编译该代码。

答案 2 :(得分:1)

另一个答案不在这里,但应该是 - 删除所有泛型语法(即删除所有<?>)。然后解析器将恢复为JDK1.4语法,这一切都可以正常工作。