2011-11-29 31 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語法,這一切都會正常工作。