AbstractMap详解


Abstract 内容很简单,但是中间还是有一些细节需要注意

学习了 Map 接口源码后,开始下一步 AbstractMap

首先我们先回顾一下Map 的族谱

1、Map 族谱

 

从图谱中可以明显的看出 AbstractMap 扮演了一个很重要的角色。

下面我们来看看 AbsctractMap 中到底有哪些东西吧

 

2、接口定义

 // 包:java.util
 package java.util;
 import java.util.Map.Entry;
 ​
 public abstract class AbstractMap<K,V> implements Map<K,V> {}

 

3、属性字段

AbstractMap 类中,一共只有两个字段 keySet values

     transient Set<K>        keySet;
     transient Collection<V> values;

按照基本知识,这两个字段是不可被序列化

不可序列化:被 static 修饰、被 transient 修饰的字段

 

4、内部类

开始之前我们还是简单回顾一下 Entry<K,V>

方法类型说明
K getKey()abstract获得键
V getValue()abstract获得值
V setValue(V value)abstract设置值
boolean equals(Object o)abstract判断与另一个对象是否相等
int hashCode()abstract获取 Hash 值
<K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey()static根据键比较大小,要求键的类型继承 Comparable
<K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue()static根据值比较大小,要求值的类型继承 Comparable
<K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp)static自定义比较器,根据键比较大小
<K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp)static自定义比较器,根据值比较大小

 

4.1 SimpleEntry

这一个类是继承了 Map 中的 内部接口 Entry<K,V>

而这里的 SimpleEntry<K,V> 不仅继承了 Map.Entry<K,V> ,还继承了 序列化的接口

4.1.1 构造方法

方法说明
SimpleEntry(K key, V value)通过键值对初始化对象
SimpleEntry(Entry<? extends K, ? extends V> entry)通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化

4.1.2 普通方法

方法说明
K getKey()获取键
V getValue()获取值
V setValue(V value)设置新的值,并且返回旧值
boolean equals(Object o)如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同
int hashCode()计算该对象的 hash 值
String toString()将该对象转化为字符串

源码

 public static class SimpleEntry<K,V>
         implements Entry<K,V>, java.io.Serializable
     {
         private static final long serialVersionUID = -8499721149061103585L;
 ​
         // 不可变引用
         private final K key;
         private V value;
 ​
         /** 通过指定键值对初始化对象 */
         public SimpleEntry(K key, V value) {
             this.key   = key;
             this.value = value;
         }
 ​
         /** 通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化 */
         public SimpleEntry(Entry<? extends K, ? extends V> entry) {
             this.key   = entry.getKey();
             this.value = entry.getValue();
         }
 ​
        /** 获取键 */
         public K getKey() {
             return key;
         }
         
         /** 获取值 */
         public V getValue() {
             return value;
         }
 ​
         /** 设置新的值,并且返回旧值 */
         public V setValue(V value) {
             V oldValue = this.value;
             this.value = value;
             return oldValue;
         }
 ​
         /** 如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同 */
         public boolean equals(Object o) {
             if (!(o instanceof Map.Entry))
                 return false;
             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
             return eq(key, e.getKey()) && eq(value, e.getValue());
         }
 ​
         /** 计算该对象的 hash 值 */
         public int hashCode() {
             return (key   == null ? 0 :   key.hashCode()) ^
                    (value == null ? 0 : value.hashCode());
         }
 ​
         /** 将对象转换为字符串,为方便输出 */
         public String toString() {
             return key + "=" + value;
         }
     }

 

4.2 SimpleImmutableEntry

 

4.2.1 接口定义

同 SimpleEntry 一样,都继承了 Map.Entry<K,V> 和 序列化接口

 public static class SimpleImmutableEntry<K,V>
         implements Entry<K,V>, java.io.Serializable{}

4.2.2 构造方法

方法说明
SimpleImmutableEntry(K key, V value)通过键值对初始化对象
SimpleImmutableEntry(Entry<? extends K, ? extends V> entry)通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化

4.2.3 普通方法

方法说明
K getKey()获取键
V getValue()获取值
V setValue(V value)这里并不能使用这个方法,调用这个方法将会直接抛出错误
boolean equals(Object o)如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同
int hashCode()计算该对象的 hash 值
String toString()将该对象转化为字符串

 

源码

 public static class SimpleImmutableEntry<K,V>
         implements Entry<K,V>, java.io.Serializable
     {
         private static final long serialVersionUID = 7138329143949025153L;
 ​
         // 不可变引用键值对
         private final K key;
         private final V value;
 ​
         /** 通过键值对初始化对象 */
         public SimpleImmutableEntry(K key, V value) {
             this.key   = key;
             this.value = value;
         }
 ​
         /** 通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化 */
         public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
             this.key   = entry.getKey();
             this.value = entry.getValue();
         }
 ​
         /** 获取键 */
         public K getKey() {
             return key;
         }
 ​
         /** 获取值 */
         public V getValue() {
             return value;
         }
 ​
         /** 这里并不能使用这个方法,调用这个方法将会直接抛出错误 */
         public V setValue(V value) {
             throw new UnsupportedOperationException();
         }
 ​
         /** 如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同 */
         public boolean equals(Object o) {
             if (!(o instanceof Map.Entry))
                 return false;
             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
             return eq(key, e.getKey()) && eq(value, e.getValue());
         }
 ​
         /** 计算该对象的 hash 值 */
         public int hashCode() {
             return (key   == null ? 0 :   key.hashCode()) ^
                    (value == null ? 0 : value.hashCode());
         }
     
         /** 将该对象转化为字符串,多用于打印对象 */
         public String toString() {
             return key + "=" + value;
         }
 ​
     }

 

4.3 思考

Question:可以看到SimpleEntry 和 SimpleImmutableEntry 几乎是 95%相似的,为什么要写这么写?

1、从方法区别上来看, SimpleEntry 是可变值,SimpleImmutableEntry 是值不可变的,也就是 SimpleEntry 的值可变

2、从内部字段来看,SimpleEntry 只有键不可变, SimpleImmutableEntry 键值都不可变

         // SimpleEntry
         private K key;
         private final V value;
         // SimpleImmutableEntry
         private final K key;
         private final V value;
 /** 错误;
     final Integer a = 1;
      a = 2;
 */

 

 

5、静态方法-eq

 

方法说明
eq(Object o1, Object o2)如果两个对象都不为空,判断两个兑对象是否相等

 

     /** 如果两个对象都不为空,判断两个兑对象是否相等 */
     private static boolean eq(Object o1, Object o2) {
         return o1 == null ? o2 == null : o1.equals(o2);
     }

 

 

6、抽象方法-entrySet

entrySet 一般用于迭代的,将其中的数据取出

方法说明
Set<Entry<K,V>> entrySet()将 Map 中的每一对键值对,存入Set中,常用于遍历

 

 public abstract Set<Entry<K,V>> entrySet();

 

 

7、普通方法

7.1 添加键值对

方法说明
V put(K key, V value)直接抛出异常,不可通过此方法新增键值对
void putAll(Map<? extends K, ? extends V> m)将传入 Map 集合中的所有键值对添加到该 Map

7.1.1  put(K key, V value)

     /** 直接抛出异常,不可通过此方法新增键值对 */
     public V put(K key, V value) {
         throw new UnsupportedOperationException();
     }

7.1.2 putAll(Map<? extends K, ? extends V> m)

 ​     /** 将传入 Map 集合中的所有键值对添加到该 Map */
     public void putAll(Map<? extends K, ? extends V> m) {
         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
             put(e.getKey(), e.getValue());
     }

 

 

7.2 获取数据

说明方法
V get(Object key)通过键获取值
     /** 通过键获取值 */
     public V get(Object key) {
         // 将键值对存储到 Set 中,将其迭代
         Iterator<Entry<K,V>> i = entrySet().iterator();
         // 寻找键为null的值
         if (key == null) {
             while (i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (e.getKey() == null)
                     return e.getValue();
             }
         } else {    //寻找 键不为 null 的的值
             while (i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (key.equals(e.getKey()))
                     return e.getValue();
             }
         }
         return null;
     }
 

7.3 移除元素

方法说明
V remove(Object key)根据键值移除键值对,并且返回键对应的值
void clear()清除 Map 中的所有的键值对

 7.3.1 remove(Object key)


     /** 根据键值移除键值对,并且返回键对应的值 */
     public V remove(Object key) {
         Iterator<Entry<K,V>> i = entrySet().iterator();
         Entry<K,V> correctEntry = null;
         if (key==null) {
             while (correctEntry==null && i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (e.getKey()==null)
                     correctEntry = e;
             }
         } else {
             while (correctEntry==null && i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (key.equals(e.getKey()))
                     correctEntry = e;
             }
         }
 ​
         V oldValue = null;
         if (correctEntry !=null) {
             oldValue = correctEntry.getValue();
             i.remove();
         }
         return oldValue;
     }

7.3.2 clear()

 ​     /** 清除 Map 中的所有的键值对 */
     public void clear() {
         entrySet().clear();
     }

 

7.4 对 Map 操作

方法说明
int size()获取 Map 中键值对的数量
Object clone()将 Map 克隆,并将其中的 keySet 和 记录所有值得 values 集合清空
boolean isEmpty()判断 Map 里面有没有东西

 7.4.1 size()


     /** 获取 Map 中键值对的数量 */
     public int size() {
         return entrySet().size();
     }
 ​

 7.4.2 clone()

     /** 将 Map 克隆,并将其中的 keySet 和 记录所有值得 values 集合清空 */
     protected Object clone() throws CloneNotSupportedException {
         AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
         result.keySet = null;
         result.values = null;
         return result;
     }

 7.4.3 sEmpty()

 ​
     /** 判断 Map 里面有没有东西 */
     public boolean isEmpty() {
         return size() == 0;
     }

 

7.5 为迭代而生 ★

这两个方法的具体实现是典型的

抽象方法中 entrySet 同样也是,只不过这里没有实现

说明方法
Set<K> keySet()keySet() 方法是将 Map 中所有的键存储到一个 Set 集合中
Collection<V> values()将 Map 中的内容存储到 Collection 集合 中,进行返回

7.5.1 keySet

使用场景:遍历的时候,通过遍历Set 取出其中的 Key ,再通过 key 获取 Value

     public Set<K> keySet() {
         Set<K> ks = keySet;
         if (ks == null) {
             ks = new AbstractSet<K>() {
                 public Iterator<K> iterator() {
                     return new Iterator<K>() {
                         private Iterator<Entry<K,V>> i = entrySet().iterator();
 ​
                         public boolean hasNext() {
                             return i.hasNext();
                         }
 ​
                         public K next() {
                             return i.next().getKey();
                         }
 ​
                         public void remove() {
                             i.remove();
                         }
                     };
                 }
 ​
                 public int size() {
                     return AbstractMap.this.size();
                 }
 ​
                 public boolean isEmpty() {
                     return AbstractMap.this.isEmpty();
                 }
 ​
                 public void clear() {
                     AbstractMap.this.clear();
                 }
 ​
                 public boolean contains(Object k) {
                     return AbstractMap.this.containsKey(k);
                 }
             };
             keySet = ks;
         }
         return ks;
     }

 

7.5.2 values

     /** 将 Map  中的内容存储到 Collection 中,进行返回 */
     public Collection<V> values() {
         Collection<V> vals = values;
         if (vals == null) {
             vals = new AbstractCollection<V>() {
                 public Iterator<V> iterator() {
                     return new Iterator<V>() {
                         private Iterator<Entry<K,V>> i = entrySet().iterator();
 ​
                         public boolean hasNext() {
                             return i.hasNext();
                         }
 ​
                         public V next() {
                             return i.next().getValue();
                         }
 ​
                         public void remove() {
                             i.remove();
                         }
                     };
                 }
 ​
                 public int size() {
                     return AbstractMap.this.size();
                 }
 ​
                 public boolean isEmpty() {
                     return AbstractMap.this.isEmpty();
                 }
 ​
                 public void clear() {
                     AbstractMap.this.clear();
                 }
 ​
                 public boolean contains(Object v) {
                     return AbstractMap.this.containsValue(v);
                 }
             };
             values = vals;
         }
         return vals;
     }

 

 

7.6 查询 Map 是否有对应的 Key/Value

方法说明
boolean containsKey(Object key)判断 Map 中是否有该键
boolean containsValue(Object value)判断 Map 中是否有该值

7.6.1 containsKey(Object key)

     /** 判断 Map 中是否有该键 */
     public boolean containsKey(Object key) {
         Iterator<Map.Entry<K,V>> i = entrySet().iterator();
         if (key==null) {
             while (i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (e.getKey()==null)
                     return true;
             }
         } else {
             while (i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (key.equals(e.getKey()))
                     return true;
             }
         }
         return false;
     }

7.6.2 containsValue(Object value)

     /** 判断 Map 中是否有该值 */
     public boolean containsValue(Object value) {
         Iterator<Entry<K,V>> i = entrySet().iterator();
         if (value==null) {
             while (i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (e.getValue()==null)
                     return true;
             }
         } else {
             while (i.hasNext()) {
                 Entry<K,V> e = i.next();
                 if (value.equals(e.getValue()))
                     return true;
             }
         }
         return false;
     }
 ​

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AbstractMapJava集合框架中的一个抽象类,它实现了Map接口。在AbstractMap类中,只有一个抽象方法:entrySet(),该方法返回一个包含Map中所有键值对的Set集合。 AbstractMap类内部还包含了操作子元素的实体接口Entry,通过Entry的视图实现,AbstractMap类可以对元素进行操作。 通过继承AbstractMap类,我们可以轻松地实现自定义的Map类,并根据需要重写其中的方法。AbstractMapJava集合中扮演着重要的角色,它提供了一些基本的实现,方便我们自定义具体的Map类。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java常用数据结构之Map-AbstractMap](https://blog.csdn.net/weixin_33957648/article/details/87959196)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Java集合类:AbstractMap](https://blog.csdn.net/yeyazhishang/article/details/83097059)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [详解JavaAbstractMap抽象类](https://download.csdn.net/download/weixin_38554781/12763008)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值