我在jdk 8示例中看到了这种声明:
Map<String, ?> map = new HashMap<>(3);//OK
但是当我尝试为“地图”添加价值时,我没有成功:
map.put("abc", Optional.of(5));
map.put("kk", "xyz");
两者均无法编译。我想知道:
(1)“是什么?”在上面的地图声明中指明?
(2)如何为该“地图”赋予值?
答案 0 :(得分:8)
Map<String,?>
是一种抽象类型。如果变量具有此类型,则它可以引用具有以下任何一种(或其他类型)的对象。
HashMap<String,Integer>
TreeMap<String,String>
HashMap<String,ArrayList<Boolean>>
TreeMap<String,Throwable>
显然,可能性基本上是无限的。如果您具有这种类型的变量,则可以知道它引用的键为String
的映射,但您实际上一无所知。特别是,您不知道在get
上执行Map
时将得到哪种对象。
但是,更重要的是,如果没有某种讨厌的,不安全的投射操作,您将永远无法put
将任何东西放入地图。编译器将阻止您。因此,在您给出的示例中-
map.put("abc", Optional.of(5));
无法编译,因为map
可能是HashMap<String,String>
,您不能在其中放入Optional
。map.put("kk", "xyz");
无法编译,因为map
可能是TreeMap<String,Integer>
,您不能在其中放入String
。例外情况可能是null
,也可能是来自地图本身的任何值-有关这些可能性的更多详细信息,请参阅安迪·特纳(Andy Turner)的出色答案。
简而言之,如果您拥有类型Map<String,?>
的变量,则编译器将允许您对其执行的操作受到一些限制。您不能将任何东西放入地图,除非它是null
或已经在地图中。您所能做的就是从地图中获取值,然后从地图中删除值。
因此,使用Map<String,?>
变量是非常有限的。如果您只想从映射中读取值,那当然很好。但是不要期望能够在地图中插入任意值,除非您使用其他表达式来引用地图。
答案 1 :(得分:6)
问题(1)
? is called wildcard generic type.It can be used with any type,
but you need to specify type fist as Map is an abstract class.
问题(2)
您可以使用“上限”或“下限”为地图赋予价值。
以下是使用上限或下限的准则
? extends Type - is used for read access only
? super Type - is used for write access only.
PECS 简而言之产生(写入权限)-使用扩展,而消耗(读取访问权限)-< strong>使用超级
Map<String, ? super Object> map = new HashMap<>(3);//OK
map.put("abc",Optional.of(5));
map.put("kk","xyz");
map.forEach((k,v)->System.out.println(k+"\t"+v));
输出
kk xyz
abc Optional[5]
Process finished with exit code 0
附加说明
无限制通配符?
List<?> l = new ArrayList<String>();
具有上限的通配符?扩展类型
List<? extends Exception> l = new ArrayList<RuntimeException>();
下限通配符?超级类型
List<? super Exception> l = new ArrayList<Object>();
答案 2 :(得分:6)
?
是未知类型:您不完全知道代码中的含义。
因此,除了几个例外,您无法安全地向地图添加任何值。
您可以添加文字null
(因为null
可以强制转换为任何类型):
map.put("abc", null); // compiles
此外,您可以向从地图获取的地图中添加一个值:
<T> void reAdd(Map<String, T> map) {
T value = map.get("123");
map.put("456", value);
}
// Call with
reAdd(map); // compiles