• Java集合类源码解析:AbstractMap


    引言

    今天学习一个Java集合的一个抽象类 AbstractMap ,AbstractMap 是Map接口的 实现类之一,也是HashMap、TreeMap、ConcurrentHashMap 等的父类,它提供了Map 接口中方法的基本实现(关于Map接口有疑惑的同学可参考 Java集合类根接口:Collection 和 Map

    源码解析

    因为 AbstractMap 类是实现Map接口的抽象类,所以其内部也包含了操作子元素的实体接口 Entry,其源码方法对元素的操作都是基于 Entry 的视图实现的。

    抽象函数entrySet()

    AbstractMap类中有一个唯一的抽象函数 entrySet() ,类中对集合视图操作的很多方法都是依赖这个抽象函数的,它返回一个保存所有 key-value 映射的Set。

    当我们要实现一个不可变的 Map 时,只需要继承 AbstractMap 类并实现 entrySet() 即可。

    如果想要实现一个可变的 Map ,我们还需要重写 put() 方法,因为 AbstractMap 类中默认不支持 put实现,子类必须重写该方法的实现,否则会抛出异常:

    public V put(K key, V value) {
        throw new UnsupportedOperationException();
    }
    

    在这里,有人会疑惑为什么必须重写 put 方法呢,很大可能是官方考虑到也许会有不可修改的Map实现子类继承 AbstractMap,如果 put 方法默认可以操作,那不可修改的子类就行不通了。

    两个集合视图

    AbstractMap没有提供 entrySet() 的实现,但是却提供了 keySet() 与 values() 集合视图的默认实现,它们都是依赖于 entrySet() 返回的集合视图实现的,这是他们的源码:

    • keySet()
    // 返回一个AbstractSet的实现,包含了所有的key
    public Set<K> keySet() {
        if (keySet == null) {
            keySet = 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);
                }
            };
        }
        return keySet;
    }
    
    • values()
    // 返回一个AbstractCollection的实现,包含了所有的value
    public Collection<V> values() {
        if (values == null) {
            values = 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);
                }
            };
        }
        return values;
    }
    

    操作方法

    下面看看 AbstractMap 的具体操作集合的方法。

    • 添加
    /**
     * 没有提供实现,子类必须重写该方法,否则调用put()会抛出异常。
     */
    public V put(K key, V value) {
        throw new UnsupportedOperationException();
    }
    /**
     * 遍历一个Map,然后将每一个键值对put到该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());
     }
    
    • 删除
    /**
     * 遍历entrySet,先找到对应的key的entry,然后删除。
     */
    public V remove(Object key) {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        Entry<K,V> correctEntry = null;
        //遍历查找,当某个 Entry 的 key 和 指定 key 一致时结束
        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();
            //调用迭代器的 remove 方法
            i.remove();
        }
        return oldValue;
    }
    /**
     * 清空entrySet,等价于清空该Map。
     */
    public void clear() {
        entrySet().clear();
    }
    
    • 查询对应的子元素
    //遍历entrySet(),看看是否包含参数key
    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;
    }
    
    //与containsKey方法同理,只是比较的是value
    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;
      }
    
    • 获取元素
    //使用 entrySet 迭代器进行遍历,根据 key 查找,返回对应的value
    public V get(Object key) {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (key==null) {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (e.getKey()==null)
                    return e.getValue();
            }
        } else {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (key.equals(e.getKey()))
                    return e.getValue();
            }
        }
        return null;
    }
    

    两个子类

    除了上面的方法之外,AbstractMap 类中还提供了两个子类,分别是 SimpleEntry,SimpleImmutableEntry,两个子类都实现了Map.Entry 以及 Serializable 接口,这是他们的源码

    • SimpleEntry
    public static class SimpleEntry<K, V> implements Entry<K, V>, Serializable {
        private static final long serialVersionUID = -8499721149061103585L;
        private final K key;
        private V value;
    
        public SimpleEntry(K var1, V var2) {
            this.key = var1;
            this.value = var2;
        }
    
        public SimpleEntry(Entry<? extends K, ? extends V> var1) {
            this.key = var1.getKey();
            this.value = var1.getValue();
        }
    
        public K getKey() {
            return this.key;
        }
    
        public V getValue() {
            return this.value;
        }
    
        public V setValue(V var1) {
            Object var2 = this.value;
            this.value = var1;
            return var2;
        }
    
        public boolean equals(Object var1) {
            if (!(var1 instanceof Entry)) {
                return false;
            } else {
                Entry var2 = (Entry)var1;
                return AbstractMap.eq(this.key, var2.getKey()) && AbstractMap.eq(this.value, var2.getValue());
            }
        }
    
        public int hashCode() {
            return (this.key == null ? 0 : this.key.hashCode()) ^ (this.value == null ? 0 : this.value.hashCode());
        }
    
        public String toString() {
            return this.key + "=" + this.value;
        }
    }
    
    • SimpleImmutableEntry
    public static class SimpleImmutableEntry<K, V> implements Entry<K, V>, Serializable {
        private static final long serialVersionUID = 7138329143949025153L;
        private final K key;
        private final V value;
    
        public SimpleImmutableEntry(K var1, V var2) {
            this.key = var1;
            this.value = var2;
        }
    
        public SimpleImmutableEntry(Entry<? extends K, ? extends V> var1) {
            this.key = var1.getKey();
            this.value = var1.getValue();
        }
    
        public K getKey() {
            return this.key;
        }
    
        public V getValue() {
            return this.value;
        }
    
        public V setValue(V var1) {
            throw new UnsupportedOperationException();
        }
    
        public boolean equals(Object var1) {
            if (!(var1 instanceof Entry)) {
                return false;
            } else {
                Entry var2 = (Entry)var1;
                return AbstractMap.eq(this.key, var2.getKey()) && AbstractMap.eq(this.value, var2.getValue());
            }
        }
    
        public int hashCode() {
            return (this.key == null ? 0 : this.key.hashCode()) ^ (this.value == null ? 0 : this.value.hashCode());
        }
    
        public String toString() {
            return this.key + "=" + this.value;
        }
    }
    

    两个实现都非常简单,具体的方法也是大同小异,唯一有区别的是 setValue 这个方法,SimpleEntry 支持 setValue 的操作实现,而 SimpleImmutableEntry 就没有实现,说明前者为可变集合,后者为不可变集合。

    参考:

    http://www.importnew.com/29686.html

  • 相关阅读:
    如何创建自己的SAP CRM产品主数据search scenario
    互联网商业数据分析(六十九):数据可视化Tableau篇(九)其他知识点
    互联网商业数据分析(六十八):数据可视化Tableau篇(八)可视化项目(二)
    互联网商业数据分析(六十七):数据可视化Tableau篇(七)可视化项目(一)
    ubuntu关闭时间同步与centos更改时间
    对比Intel和Kunpeng+ openEuler
    pci config + resource
    IORESOURCE_MEM IORESOURCE_IO
    PCIE的mmio内存映射访问机制+ 配置空间 +mmap + resource + /dev/mem
    mmap PROT_READ | PROT_WRITE
  • 原文地址:https://www.cnblogs.com/yeya/p/9950667.html
Copyright © 2020-2023  润新知