2016-09-28 102 views
2

我是java新的泛型,面臨以下問題。 我也有類似的方法,爲什麼HashMap <String,Object>不接受HashMap <String,List>實例?

private static void fillDescriptiveData(HashMap<String, Object> output, String attributeMapping) { 
    for (Map.Entry<String, Object> outputInEntry : output.entrySet()) { 
     String outputKey = outputInEntry.getKey(); 
     String outputValue = outputInEntry.getValue().toString(); 
     outputValue = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
     outputInEntry.setValue(outputValue); 
    } 
} 

現在,如果我叫API如下方式

HashMap<String, Object> ObjectMap = new HashMap<String, Object>(); 
HashMap<String, List> listMap = new HashMap<String, List>(); 
  • fillDescriptiveData(ObjectMap,"here");
    這一項工作的罰款。

  • fillDescriptiveData(listMap,"here"); 此呼叫給出錯誤

方法fillDescriptiveData(HashMap中,字符串)在類型CustomAttribute不適用於參數(HashMap中,字符串)`

爲什麼?

在行來解決這個問題,我有一個更多的問題遇到,在線

private static void fillDescriptiveData(HashMap<String, ? extends Object> output, String attributeMapping) { 
    for (Map.Entry<String, ? extends Object> outputInEntry : output.entrySet()) { 
     String outputKey = outputInEntry.getKey(); 
     String outputValue = outputInEntry.getValue().toString(); 
     outputValue = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
     outputInEntry.setValue(outputValue); /* Error comes at this line */ 
    } 
} 

HashMap<String, ? extends Object> ObjectMap = new HashMap<String, Object>(); 
HashMap<String, List> listMap = new HashMap<String, List>(); 
fillDescriptiveData(ObjectMap,"here"); 
fillDescriptiveData(listMap,"here"); 

錯誤 - outputInEntry.setValue(outputValue);

的方法SetValue在(?捕獲#4的擴展對象)類型 Map.Entry不適用於 的參數(字符串)

爲什麼?

避免此問題的最佳方法是什麼?

+1

你的第二個 「爲什麼?」問:「爲什麼我不能在字符串中放置一個字符串作爲值,答案是」因爲靜態類型系統正在完成它的工作「 –

+2

反正你試圖做的顯然是壞的,你的方法'fillDescriptiveData'將你的'HashMap '轉換爲'HashMap '這顯然是違規的,那麼不要使用泛型,如果你想轉換一個番茄成一個胡蘿蔔,並把結果放入同一個集合 –

+0

如何處理像'Map getDescriptiveData(HashMap output,String attributeMapping){...}'? - 此外,您的問題標題是誤導性的,你可能想編輯它 – JimmyB

回答

2

這是當你可以使用類型變量的情況:

private static <T> void fillDescriptiveData(Map<String, T> output,String attributeMapping) 
{ 
    for(Map.Entry<String, T> outputInEntry : output.entrySet()) 
    { 
     String outputKey = outputInEntry.getKey(); 
     String outputValue = outputInEntry.getValue().toString(); 
     outputValue = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
     outputInEntry.setValue((T) outputValue); 
    } 
} 

更具體地說,在地圖上你的第二個類型參數是無界的。 Object在這裏不起作用,因爲它是特定的類。 ? extends Object有點廢話。 只需HashMap<String, ?>就可以工作,直到您只會閱讀地圖爲止,但您無法在此處放置任何東西。所以只有一種方法 - 使用類型變量。

編輯:還有一件事:請使用接口,這是可能的。所以這裏代替HashMap<String, T>更好用Map<String, T>。這不是一個錯誤,只是良好和正確的代碼風格。

+0

顯然你期望'String outputValue'可以被轉換成任意的'T'。 –

+0

@MarkoTopolnik我同意,這很奇怪,我沒有注意到。將工作,因爲在運行時你可以把任何值進入地圖:) – Andremoniy

+0

有意義的方法簽名是'Map 地圖,T值)',但這似乎並不是OP所要做的。他似乎正在做一些相當糟糕的事情。 –

1

這一行的錯誤:

outputInEntry.setValue(outputValue); 

這就是你永遠把一個字符串到項。這僅適用於條目類型爲? super String或確切String。所以它不適用於Map<String, Object>Map<String, List>

看起來你只是想將每個值映射到一個字符串。你可以做到這一點,但爲了安全起見,你需要創建一個新的Map<String, String>。由於您總是映射到String

如果您例如傳入Map<String, List<?>>和(不安全地)將所有值替換爲字符串。有人仍然可以繼續使用傳遞給函數的Map<String, List<?>>,但它現在包含字符串作爲值而不是列表。當他們嘗試從中檢索List時,他們會得到類轉換異常。

事情是這樣的:

private static Map<String, String> fillDescriptiveData(HashMap<String, ?> input, 
     String attributeMapping) {   
    Map<String, String> output = new HashMap<>(); 

    for(Entry<String, ?> e : input.entrySet()) { 
      String outputKey = e.getKey(); 
      String outputValue = e.getValue().toString(); 
      outputValue 
       = getDescriptiveDataForOutput(outputKey, outputValue, attributeMapping); 
      output.put(outputKey, outputValue); 
    } 
    return output; 
} 
Map<String, String> r1 = fillDescriptiveData(ObjectMap, "here"); 
Map<String, String> r2 = fillDescriptiveData(listMap, "here"); 
+0

此聲明「這隻會起作用」並不準確。正如我在答覆中所說的那樣,它將與類型變量一起工作。類型的實際不匹配不是關鍵問題,因爲運行時地圖可以保存任何類型的值 – Andremoniy

+0

@Andremoniy當然,也許我應該添加「正確」或「以類型安全的方式」。 –

相關問題