对于所有Map对象本质都是key to value的映射——其实就是离散函数,连续函数是无穷多个元素(键值对)的集合,离散函数(Map)是有限个元素(键值对)的集合,key在Map中不可重复出现(不然就违反了函数的定义)。
用通俗点的角度来看Map和字典是同一个概念——字典中的每个字(相当于Map中的key)都对应这个字的解释和相关信息(相当于Map中的value),从数学和逻辑的角度字典中的字列表不应该出现同一个字(多音字在字典子列表中的重复存在其实是没有必要且有害的,每个字的解释都应该标明其所有读音及解释,而不是通过读音找到相应的字然后再找解释)。其实在jdk中有java.util.Dictionary这么一个抽象类,Map就相当于它的interface版本(规定的功能要更多)。
Map接口提供了3个“collection views”,包括:
- Map中包含所有keys的Set;
- Map中包含所有values的collection;
- Map中包含所有键值对的Set。
注意上面3个“collection views”返回的集合是否有序取决于Map的实现类是否有序,像TreeMap返回的都会是有序的,但HashMap返回的就是无序的。有一点要特别提醒上面3个集合都是“is backed by the map”的,换句话说,改动他们将会影响原Map对象(比如删除里面的元素,原Map的键值对也会被删除)
Map<Integer, String> map = new HashMap<>();
map.put(1, "1");
Set<Integer> keys = map.keySet();
keys.remove(1);
System.out.println(map);
有一种情况比特别提醒一下。如果选为key的类是可变且这种可变性会影响到equals()和hashCode()的返回值,那么则不应该选择这种类的对象作为key(很多Map的实现类都是通过对象的hashCode()和equals()的返回值来确定key和value的映射关系的,Map的骨架实现类AbstractMap就是其中之一)。举个例子:Map对象就不应该作为key来存进Map中,很多Map的实现类其hashCode()和equals()的返回值就是随着键值对的变化而变化的,随着Map的实时变化会导致映射关系不断变化,表现就是查不到Map中keyMap所对应的value。
使用Map中方法的一些小技巧:
- Map.get(Object key)返回为null,不一定表示Map.containsKey(Object key)返回false,毕竟有些Map的实现类是允许value为null的。
- 在jdk1.8中新增了好几个比较实用的默认方法:getOrDefault(Object key, V defaultValue)、putIfAbsent(K key, V value)、remove(Object key, Object value)、replace(K key, V oldValue, V newValue) 。这些方法都有一个共同的特点——确定旧值之后,再判断是否进行操作。
举个例子:对于Map<Integer, Double> rankToRate; 对于这么一个Map,key表示等级,value表示倍率。我们传进一个等级key,如果刚好这个等级不存在于rankToRate中,使用get(Object key)就会返回null,为保证程序的健壮我们还要在外部对null做特殊的处理。如果使用getOrDefault(Object key, V defaultValue)就可以保证在没有这个等级key的时候返回默认倍率1.0