2011-11-29 30 views
5

我有代码具有(消息)处理程序的Map。我试图让处理程序基因组化(如接口处理程序所见)。没有泛型,处理程序都需要从Object转换到相应的类,这很好避免(但一切正常)。对于每个消息类(下面的Foo),我有一个处理程序类。Java泛型:捕获不能应用于对象

我该如何将任何类别的地图保存到任何类型的处理程序中,并用“just”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 {} 
} 

此代码生成:

Logic.java:16:执行在Logic.Handler(捕获#的X')不能应用于>到(java.lang.Object中) 处理程序。执行(MSG);

如何在维持Handler接口一般性的同时修复此问题?

回答

6

您不能定义键和字段中的值之间的关系,但可以使用访问器方法来强制执行它,只要使用这些方法访问映射即可。

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

你的答案让我能够输入安全的异构容器,关系泛型类型和whatnot!我有点失望,没有包装方法和@SuppressWarnings是不可能的:<。尽管如此,它现在可行,但我不知道是否值得在这里引入泛型的麻烦。 –

+0

问题是你想要通用语法是多么复杂。 ;)它将检查对addHandler,hetHandler和getHandlerFor的调用是否正确。 –

2

的问题是,​​花费一定的参数类型,即比Object更具体。

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

在这种情况下实际上handler.execute(msg);将导致FooHandler#execute(Foo)被称为具有Bar参数,这将导致在一个ClassCastException(除非Bar extends Foo)。因此,编译器拒绝编译该代码。

+0

好点! –

1

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