Java中的Map【一】Map接口 2021-09-21 07:04 216阅读 0赞 # 一 JDK中的Map继承实现关系 # 不经意间看了Java中LinkedHashMap和LinkedHashSet的源码实现,觉得一些地方还是挺有意思的。之前阅读过一些,但没有进行系统性地总结,打算尝试一下Map源码的系统性整理学习。因为Java中的Set底层基本上是借助对应的Map实现的,故Set打算放在Map之后学习。**所使用的jdk版本为1.8版本**,先看一下JDK中Map的UML类图: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDc2MzQ1_size_16_color_FFFFFF_t_70][] 这张图囊括了JDK中绝大部分的Map(没有将java.util.Collections中的一些private static map结构、java.util.EnumMap等列入),后面逐一分析,希望能有所收获。 # 二 源码分析学习 # ## 2.1 相关接口 ## ### 2.1.1 Map接口 ### Map<K,V>是最基本的接口,它表示将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。此接口被设计用来取代 java.util.Dictionary 类,后者完全是一个抽象类,而不是一个接口。因为Map涉及到Key和Value两个对象,所以它不像List<E>或者Set<E>接口都实现了Collection<E>接口,Map<K,V>没有继承任何接口。有些Map的实现可以保证顺序,如TreeMap;有些Map的实现不保证顺序,如HashMap;还有特殊的Map实现比如LinkedHashMap具有可预知的迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。 下面列一些需要注意的地方: **2.1.1.1 containsKey(Object key)方法** Map中需要注意的containsKey(Object key)方法,Map是否已经包含有某个对象key的判断条件:**当且仅当此映射包含针对满足 (key==null ? k==null : key.equals(k)) 的键 k 的映射关系时,返回 true。(最多只能有一个这样的映射关系)。**可能日常开发中常用字符串String作为key,而String已经帮我们实现了Object类中的equals()方法和hashCode()方法,所以当我们使用自定义的对象作为key时,一定要考虑这两个方法的实现。containsKey(Object key)定义如下: /** * Returns <tt>true</tt> if this map contains a mapping for the specified * key. More formally, returns <tt>true</tt> if and only if * this map contains a mapping for a key <tt>k</tt> such that * <tt>(key==null ? k==null : key.equals(k))</tt>. (There can be * at most one such mapping.) * * @param key key whose presence in this map is to be tested * @return <tt>true</tt> if this map contains a mapping for the specified * key * @throws ClassCastException if the key is of an inappropriate type for * this map * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified key is null and this map * does not permit null keys * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>) */ boolean containsKey(Object key); **2.1.1.2 entrySet()方法和内部接口Entry<K,V> ** Map接口中还定义了一个内部接口Entry<K,V>,用来表示Map中的映射项;另外有一个方法Set<Map.Entry<K, V>> entrySet();两者结合可以用来遍历Map中的元素。比如下面写法: for (Map.Entry<String, Object> entry : map.entrySet()) { System.out.println("key:value = " + entry.getKey() + ":" + entry.getValue()); } **2.1.1.3 V put(K key, V value)方法** 将映射关系放入Map结构中,需要注意的是如果此映射以前包含一个该键的映射关系,则用指定值替换旧值(当且仅当m.containsKey(k)返回 true 时,才能说映射 m 包含键 k 的映射关系)。 返回值:返回之前与 key 关联的旧值,如果没有针对 key 的映射关系,则返回 null。(如果该实现支持 null 值,则返回 null 也可能表示此映射以前将 null 与 key 关联)。 **2.1.1.4 Set<K> keySet() 和 Collection<V> values()** ** ** Set<K> keySet()方法返回Map中所有映射关系中key的集合,因为key是不能重复的,所以返回的是Set结构;Collection<V> value()方法返回Map中所有映射关系值value的集合,value的值是可以重复的,所以返回的是Collection结构,重复的value值也会重复返回,不会去重。 通过keySet()方法和get(Object key)方法也能遍历Map: for (String key : map.keySet()) { System.out.println("map.get(" + key + ") = " + map.get(key)); } **2.1.1.5 equals(Object o) 和 hashCode()** ** ** equals(Object o)方法用来比较两个Map是否相等,如果给定的对象也是一个映射,并且这两个映射表示相同的映射关系,则返回 true。更确切地讲,如果 m1.entrySet().equals(m2.entrySet()),则两个映射 m1 和 m2 表示相同的映射关系。 hashCode()方法返回此映射的哈希码值。映射的哈希码定义为此映射 entrySet() 中每个项的哈希码之和。这确保 m1.equals(m2) 对于任意两个映射 m1 和 m2 而言,都意味着 m1.hashCode()==m2.hashCode(),正如Object.hashCode()中的要求。 equals(Object o)和hashCode()的具体实现,可以参考java.util.AbstractMap中的实现,后面也会介绍。 **2.1.1.6 JDK1.8版本新增加的特性** **1、default V getOrDefault(Object key, V defaultValue)** 一个default方法,返回Map中key对应的value值,如果没有这个key,返回传入的默认值defaultValue: default V getOrDefault(Object key, V defaultValue) { V v; return (((v = get(key)) != null) || containsKey(key)) ? v : defaultValue; } 使用示例: public static void main(String[] args) { Map map = new HashMap(); map.put("1", 12); map.put("11", 12); map.put("12", 13); System.out.println(map.getOrDefault("11",120)); System.out.println(map.getOrDefault("13",120)); } 输出结果: 12 120 **2、default void forEach(BiConsumer<? super K, ? super V> action) ** 该forEach方法采用函数式编程,传入一个函数式接口BiConsumer,用来迭代遍历Map,如下: map.forEach((k, v) -> System.out.println("key:value = " + k + ":" + v)); **3、default void repalceAll(BiFunction<? super K, ? super V> action) ** default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { Objects.requireNonNull(function); for (Map.Entry<K, V> entry : entrySet()) { K k; V v; try { k = entry.getKey(); v = entry.getValue(); } catch(IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } // ise thrown from function is not a cme. v = function.apply(k, v); try { entry.setValue(v); } catch(IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } } } 用给定的函数action对Map中的每个映射进行处理,并用每个映射执行action返回的结果替换映射对应的value值。举个例子: public static void main(String[] args) { Map<String,Integer> map = new HashMap(); map.put("1", 1); map.put("2", 2); map.put("3", 3); System.out.println(map); //对map中的每个映射value值都加1 map.replaceAll((k,v) -> v +=1); System.out.println(map); } 输出结果: {1=1, 2=2, 3=3} {1=2, 2=3, 3=4} **4、default V putIfAbsent(K key, V value)** default V putIfAbsent(K key, V value) { V v = get(key); if (v == null) { v = put(key, value); } return v; } ** **如果入参中的key在Map中没有映射的value值或者映射的value值为null,把入参中的value值与之关联,返回null。反之,返回Map中该key映射的value值。 使用示例: public static void main(String[] args) { Map<String, Integer> map = new HashMap(); map.put("1", 1); map.put("2", null); System.out.println("初始map:" + map); System.out.println("map.putIfAbsent(\"1\", 11)返回值:" + map.putIfAbsent("1", 11)); System.out.println("map.putIfAbsent(\"2\", 2)返回值:" + map.putIfAbsent("2", 2)); System.out.println("map.putIfAbsent(\"3\", 3)返回值:" + map.putIfAbsent("3", 3)); System.out.println("处理后map:" + map); } 输出结果: 初始map:{1=1, 2=null} map.putIfAbsent("1", 11)返回值:1 map.putIfAbsent("2", 2)返回值:null map.putIfAbsent("3", 3)返回值:null 处理后map:{1=1, 2=2, 3=3} ** 注:还有一些其它的default函数,这里不再一一列举了,都是JDK1.8中根据default特性新加在Map接口中的,大家可以自己了解下,实际开发使用会便利一些。** 以上,Map接口暂时就写这么多~ [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIyMDc2MzQ1_size_16_color_FFFFFF_t_70]: /images/20210920/2d80284f4f5449b9880dd5c41e9c59fc.png 文章版权声明:注明蒲公英云原创文章,转载或复制请以超链接形式并注明出处。
相关 Java中的Map【一】Map接口 一 JDK中的Map继承实现关系 不经意间看了Java中LinkedHashMap和LinkedHashSet的源码实现,觉得一些地方还是挺有意思的。之前 谁借莪1个温暖的怀抱¢/ 2021年09月21日 07:04/ 0 赞/ 217 阅读
相关 Java中的Map【三】NavigableMap接口 所使用的jdk版本为1.8版本,先看一下NavigableMap<K,V>在JDK中Map的UML类图中的位置: ![watermark_type_ZmFuZ3 一时失言乱红尘/ 2021年09月21日 07:14/ 0 赞/ 252 阅读
相关 Java中的Map【四】ConcurrentMap接口 所使用的jdk版本为1.8版本,先看一下ConcurrentMap<K,V>在JDK中Map的UML类图中的位置: ![watermark_type_ZmFuZ3poZW5n 港控/mmm°/ 2021年09月21日 07:20/ 0 赞/ 244 阅读
相关 Java中的Map【五】ConcurrentNavigableMap接口 所使用的jdk版本为1.8版本,先看一下ConcurrentNavigableMap<K,V>在JDK中Map的UML类图中的位置: ![watermark_ 刺骨的言语ヽ痛彻心扉/ 2021年09月21日 07:24/ 0 赞/ 226 阅读
相关 Java-map接口 package java.util;//在util包下 public interface Map<K,V> {//K:key,v:value //1 约定不等于承诺〃/ 2021年09月28日 09:22/ 0 赞/ 282 阅读
相关 java-Map接口 Map接口的概述和使用 -概述:public interface Map<K,V> -特点:\将键映射到值的对象 \一个映射不能包含重复的键 深藏阁楼爱情的钟/ 2022年01月28日 22:53/ 0 赞/ 159 阅读
相关 java中的Map接口 java中的Map接口 实现Map接口的类用来存储——键值对 Map接口的实现类有HashMap和TreeMap等 键值不能重复(键相当与索引) TestMap. 水深无声/ 2022年04月06日 17:40/ 0 赞/ 115 阅读
相关 java map接口 Map接口概述 1. 实现Map接口的集合类用来存储“键-值”映射对。key-value 2. Map实现类中存储的“键-值”映射对是通过键来唯一标识,Map底层的“键 ╰+攻爆jí腚メ/ 2022年06月10日 09:54/ 0 赞/ 69 阅读
相关 java Map 接口 1 保存形式: key ---- value 的方式保存 例 小雪 :1424242 2 /常用子类: HashMap: 无序存放 key 不容许重复 Hashtab 妖狐艹你老母/ 2022年06月15日 15:29/ 0 赞/ 69 阅读
相关 java的Map接口 [java的Set接口][java_Set] 文章目录 java的Map接口 Map的创建 Map的常用方法 矫情吗;*/ 2022年10月19日 12:19/ 0 赞/ 47 阅读
还没有评论,来说两句吧...