映射
映射用来存放键值对。
基本映射操作
Java中有HashMap
和TreeMap
两个类实现了Map接口,前者基于散列表,对建进行散列,后者用键的整体顺序对元素进行排序,并将其组织成搜索树,效率前者快一点。
使用Map接口的get方法时,如果key不存在,则会返回null
,如果希望有一个更好的默认值,可以使用getOrDefault(Object,Object)
,当没有结果是,使用第二个参数。
更新映射项
以自增1为例,有以下几种方法
counts.put(word,counts.get(word) + 1);
这种写法容易造成空指针异常,在word第一次出现的时候counts.put(word,counts.getOrDefault(word,0) + 1);
counts.putIfAbsent(word,0);
counts.put(word,counts.get(word) + 1);
//保证非空
所以以后不应该再用:1 2 3
if(counts.get(word) == null){ counts.put(word,0); }
counts.merge(word, 1, Integer::sum);
这个写法比较高级,书上没写太清楚,我看了下源码:1 2 3 4 5 6 7 8 9 10 11 12 13
default V merge(K var1, V var2, BiFunction<? super V, ? super V, ? extends V> var3) { Objects.requireNonNull(var3); Objects.requireNonNull(var2); Object var4 = this.get(var1); Object var5 = var4 == null ? var2 : var3.apply(var4, var2); if (var5 == null) { this.remove(var1); } else { this.put(var1, var5); } return var5; }
先取key为word
的值,如果为空,直接将第二个参数作为word的值put到map中,如果不为空,根据给出的函数式接口(这里我们使用Integer::sum
方法)计算原值和给出的第二个参数的和并返回。
映射视图
Set<K> keySet()
键集Collection<V> values()
值集Set<Map.Entry<K,V>> entrySet()
键值对集
在键集视图上调用迭代器的remove方法,实际上会从映射中删除这个键和与它关联的值,并且不能向键集中增加元素。
如果试图调用add方法,则会报UnsupportedOperationException
异常。
弱散列映射WeakHashMap
JVM的垃圾回收机制中,如果一个对象没有任何引用了的话,就会在下一次GC中被回收,如果在映射中,一个键对应的值如果没有任何引用,是不会被回收的,因为垃圾回收针对的是对象,这个值依附Map存在,只要Map还存在引用没有被回收,这个值也不会被回收。WeakHashMap
和HashMap
的区别是,WeakHashMap
使用弱引用(Weak Reference)保存键。Weak Reference对象将引用保存到另外一个对象中这里就是散列键。
当垃圾收集器发现某对象只被一个弱引用引用时,会将这个对象回收,并且会将这个散列键放入一个队列中,WeakHashMap
周期性的检查这个队列,如果发现有弱引用进入了队列,就删除对应的条目。
链接散列集LinkedHashSet
与链接映射 LinkedHashMap
上篇说到的基于散列表Set和Map中的元素都是无序的,但是LinkedHashSet
LinkedHashMap
中的元素是有序的,因为这两个类型在实现散列表的基础上加了一个双向链表。
当条目插入到表中时,就会并入双向链表中
链接散列映射将用访问顺序而不是插入顺序对映射条目进行迭代。也就是说,每当读写链接散列映射中的元素时,受到影响的条目会从当前位置删除,并放到双向链表的尾部,由于双向链表和散列表独立,所以并不会影响原来的存储结构。
枚举集与映射EnumSet
EnumMap
枚举集EnumSet
用来存储枚举类型,使用静态工厂方法构造枚举集
枚举映射EnumMap
表示键为枚举类型的映射EnumMap<WeekDay,Integer> weekDays = new EnumMap<>(WeekDay.class);
EnumSet
类源码中,对这个类的定义有如下:
|
|
其中<E extends Enum<E>>
表示类型参数扩展了Enum<E>
,意思就是,E是枚举类型。所有的枚举类型都是扩展了泛型Enum类。
视图与包装器
除了之前介绍的一些对Collection和Map的实现类,Java类库中还有很多能够直接获得的集合对象,比如,给定一个Map,Map中有一个方法,可以返回所有键的集合,通过这个集合可以对原映射操作。
这种集合就叫做视图。
轻量级集合包装器
Arrays.asList
…
子范围
subList
subSet
…
不可修改的视图
当得到一个unmodifiableCollection
时,它的equals
方法不调用底层集合的equals
方法,直接进行对象判等。
同步视图
Map<String, Integer> map = Collections.synchronizedMap(new HashMap<String,Integer>());
这个方法实际上接收一个Map,返回一个SynchronizedMap
类型的对象。在使用get,put方法时,下一个操作必须等到上一个操作结束之后才能进行。
受查视图
Collections.checkedList(strings,String.class);
视图的Add方法检查插入的对象是否属于给定的类,如果不属于,直接抛出ClassCastException
异常。