2017-08-07 49 views
-1

我已經聲明它包含長型的鍵的嵌套式地圖無法把對象在一個通用的地圖

嵌套地圖映射具有 基本上我想類型SomeClient的類型類的密鑰和值的地圖生成Class類型到產生Class類型響應的客戶端的映射。

private static final Map<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>> someClientMap 
     = new HashMap<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>>(); // <? super GenericResponse> should enable me to put subclasses of type GenericResponse in the Map 

的getSomeClient方法是接受的類類型作爲參數,並返回它產生類類型的應答的客戶機的通用方法(的類類型只能是GenericResponse的子類:通知類型參數中的方法簽名)

public static <T extends GenericResponse> SomeClient<T> getSomeClient(long clientId,Class<T> clazz) throws IOException { 
    if (someClientMap.get(clientId) == null) { 
     synchronized (someClientMap) { 
      someClientMap.put(clientId, new HashMap<Class<T>,SomeClient<T>>()); //getting error here      
     } 
    } 
    return someClientMap.get(clientId); 
} 

問題是我得到一個編譯時錯誤,我試圖把客戶端放在地圖中。

確切的錯誤是

The method put(Long, Map<Class<? super GenericResponse>,SomeClient<? super GenericResponse>>) in the type Map<Long,Map<Class<? super GenericResponse>,SomeClient<? super GenericResponse>>> is not applicable for the arguments (long, HashMap<Class<T>,SomeClient<T>>) 

我有困難指出究竟我做錯了。請幫忙。

宣言SomeClient是

public class SomeClient<T extends GenericResponse> 

,並在構造器是

public SomeClient(Class<T> clazz) 
+0

看起來問題出現在'長'與'長' - 你正在放置'長'參數,地圖期望'長'。添加投射或使用'Long.valueOf(。)'方法 –

+0

您可以在問題中發佈'SomeClient'和'GenericResponse'聲明嗎? –

回答

0

有在你的代碼的幾個問題。首先,如果你想允許亞型你應該使用extends而不是super

private static final Map<Long, Map<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>> someClientMap 
     = new HashMap<Long, Map<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>>(); 

這是告訴您允許的GenericResponse亞型的MapClassSomeClient泛型參數,但它不會讓你使用Class(與SomeClient相同)的子類型,對於我們所知的全部Class<T>(其中T extends GenericResponse)是Class<? extends GenericResponse>的子類型,因爲前者是特定T的後者的「專業化」。

使用該定義必須把在外之一,當使內Map的相同的通用參數:

someClientMap.put(clientId, new HashMap<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>()); 

你可以保持put因爲你擁有了它,雖然,如果你只需要添加更多extends初始聲明允許ClassSomeClient亞型:

private static final Map<Long, Map<? extends Class<? extends GenericResponse>, ? extends SomeClient<? extends GenericResponse>>> someClientMap 
     = new HashMap<Long, Map<? extends Class<? extends GenericResponse>, ? extends SomeClient<? extends GenericResponse>>>(); 

然後你可以這樣做:

someClientMap.put(clientId, new HashMap<Class<T>, SomeClient<T>>()); 

無論哪種方式,訪問someClientMap當你不會從醜陋擅自拋棄:

return (SomeClient<T>) someClientMap.get(clientId).get(clazz); 
+0

感謝您的回答,但我已經使用超級而不是擴展,因爲我想將GenericType類的不同子類添加到相同的地圖。請參考這個問題https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java進行解釋。 –

+0

@ rohit.agrawal你甚至讀過這個問題的答案嗎?這很簡單:如果你想讓GenericType的**子類**使用'?擴展GenericType';如果你想讓GenericType的**超類**使用'?超級GenericType「。 –

+0

我不只想在地圖中允許GenericType的一個子類,我想允許在同一個地圖中有多個子類型。在鏈接中複製答案的某些部分以強調我所說的內容。如果一個列表被聲明爲'List <?擴展Number> foo3';您不能添加整數,因爲foo3可能指向列表。 您不能添加Double,因爲foo3可能指向列表。 您不能添加數字,因爲foo3可能指向列表。 –

0

該錯誤是由於這樣的事實:Java泛型是不變,即雖然StringObject亞型下面一行將無法編譯:

Map<Long, Object> map = new HashMap<Long, String>(); 

因爲Map<Long, String>不是Map<Long, Object>一個亞型。

但是,我們可以通過使用界通配符,克服這種限制,即

Map<Long, ? extends Object> map = new HashMap<Long, String>(); 

這爲什麼會出現在你的代碼Class<? super GenericResponse>,但你停止大約一半。你應該使用相同的技術在未來的上層,即寫:

Map<Long, Map<? extends Class<? extends GenericResponse>, ? extends SomeClient<? extends GenericResponse>>> 

,而不是

Map<Long, Map<Class<? extends GenericResponse>, SomeClient<? extends GenericResponse>>> 

通過我在我的例子取代? super? extends的方式,因爲我覺得你不沒有正確使用它們。

-1

我想出了這個問題。在以下聲明中

someClientMap.put(clientId, new HashMap<Class<T>,SomeClient<T>>()); 

我創建的新HashMap比外部地圖接受的限制性更強。因爲T在泛型方法中擴展了GenericResponse。

聲明允許GenericResponse類的不同的子類存儲在同一地圖,因爲我使用的超級

private static final Map<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>> someClientMap 
    = new HashMap<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>>(); // <? super GenericResponse> should enable me to put subclasses of type GenericResponse in the Map 

請參閱Difference between <? super T> and <? extends T> in Java爲同一個很好的交代。

要解決我更換了放聲明

someClientMap.put(clientId, new HashMap<Class<? super GenericResponse>,SomeClient<? super GenericResponse>>()); 

這樣就把確保了內部地圖的確可以保持GenericResponse類的不同的子類的實例作爲初始宣言中聲明的問題。

private static final Map<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>> someClientMap 
    = new HashMap<Long, Map<Class<? super GenericResponse>, SomeClient<? super GenericResponse>>>(); 
+0

你用'?超級GenericResponse'但在文本你說,你需要爲「持有不同的** **子類的'GenericResponse'類的實例」 - 這是混亂的,無論是使用'?超級GenericResponse'並說「GenericResponse'類的超類或使用'?延伸GenericResponse'說 –

+0

「的'GenericResponse'類的子類」當我使用「? super GenericResponse>並說「保存GenericResponse類的不同子類的實例」我的意思是。這有點違反直覺,但事實就是這樣。請詢問https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java接受的答案爲同一個很好的解釋。 –

+0

你是對的,謝謝你的鏈接 –