2016-09-28 106 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当然,也许我应该添加“正确”或“以类型安全的方式”。 –

相关问题