Java集合系列(九)-Map、AbstractMap等

Map是一种key、value类型是数据结构,key不允许有重复,不同的Map实现对null有不同的要求。

在Java中,Map的类结构如下图所示:


java map最大容量 java map的最大上限_比较器


一、Map源码

我们先看Map的源码。


package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * 是一种映射keys到values的对象。一个map中不允许包含重复的keys,每个key最多映射一个值。
 * 这个接口代替了Dictionary类,Dictionary是一个抽象类而不是一个接口。
 * 
 * Map接口提供了三个集合视图,这些视图允许将映射的内容看作键集、值集或键值映射集。
 * 一个map的顺序是基于map返回元素的集合迭代器的顺序定义的。一些map比如TreeMap保证了元素
 * 的顺序,其他的比如hashMap并没有保证。
 *
 * 所有一般的map实现类应该提供两个标准的构造函数:无参的,和以Map作为参数的,以map作为参数的
 * 生产一个新的map和参数有着相同的key和value.
 * 一些Map实现对他们包含的key和value有限制。比如有的map实现禁止null的Key和value,,一些限制他们呢key的类型和。 尝试去插入一个不合格的key或者value将会抛出一个为检查异常,典型的异常有
 * NullPointerException或者ClassCastException。
 * 如果尝试去查询已经存在的被限制的key或valud可能会抛出异常或者返回false,有些实现将禁止前者
 * 而有些实现禁止后者。
 */
public interface Map<K,V> {
    // 查询操作

    /**
     * 返回这个map种key-value映射关系的数量。如果map包含超过Integer.MAX_VALUE,那么返回
     * Integer.MAX_VALUE
     */
    int size();

    /**
     * 如果这个map中有元素返回true
     */
    boolean isEmpty();

    /**
     * 如果这个map包含指定的key返回true.
     * 
     */
    boolean containsKey(Object key);

    /**
     * 如果这个map中包含一个或者更多指定的value那么返回true
     * 对于map接口的大多数实现,此操作可能需要映射大小的时间线性关系。
     */
    boolean containsValue(Object value);

    /**
     * 返回指定key对应的value,如果没有的话返回null
     * 如果该映射允许null值,则返回null值并不一定表示该映射不包含键的映射;
     * 也有可能映射显式地将键映射为null。containsKey操作可以用来区分这两种情况。
     */
    V get(Object key);

    // 修改操作

    /**
     * 将指定的key和value联系到一起,如果map中之前包含了指定key,那么旧值将会被替代
     * 当且仅当containsKey(对象m.containsKey(k)将返回true)返回true时,映射m将包含键k的映射。
     */
    V put(K key, V value);

    /**
     * 根据指定的key移除这个map中的key-value映射如果存在这样的映射的话。
     * 返回值是被删除的value,或者null如果没有对应的映射的话。
     * 一旦调用此方法之后,此map中将不再包含指定的对应关系。
     */
    V remove(Object key);


    // 容量操作

    /**
     * 复制所有的映射从指定的map关系中到this map中。
     */
    void putAll(Map<? extends K, ? extends V> m);

    /**
     * 移除this map中所有的映射关系,调用此方法后map中将会是空的。
     */
    void clear();


    // Views

    /**
     * 返回this map中的key的set视图。
     * set基于map,如果map改变了那set也跟着改变
     */
    Set<K> keySet();

    /**
     * 返回map中value的集合。
     */
    Collection<V> values();

    /**
     * 返回一个此map的EntrySet
     */
    Set<Map.Entry<K, V>> entrySet();

    /**
     * 一个map的entry(key-value对)类。Map.entrySet方法返回此类的元素的map集合视图。
     * 只有一种方式获取map的entry引用就是迭代器。
     * 这些Map.Entry对象只在迭代期间是有效的。
     */
    interface Entry<K,V> {
        /**
         * 返回entry中的key
         */
        K getKey();

        /**
         * 返回entry中的value
         */
        V getValue();

        /**
         * 代替这个entry中对应的值。
         */
        V setValue(V value);

        /**
         * 比较指定的对象与this entry。
         * 返回true如果指定的对象也是this entry并且两个entry代表相同的映射。
         * 通常,如果e1和e2有相同的映射要满足下面的关系比较:
         * if
         *     (e1.getKey()==null ?
         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))
         *     (e1.getValue()==null ?
         *      e2.getValue()==null : e1.getValue().equals(e2.getValue()))
         */
        boolean equals(Object o);

        /**
         * 返回此map entry的hashCode值。一个map entry的hashCode值按照如下定义:
         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
         * 这个确保e1.equals(e2) 意味着 e1.hashCode()==e2.hashCode()。
         */
        int hashCode();

        /**
         * 返回一个比较器按照key的自然顺序比较Map.Entry。
         */
        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
        }

        /**
         * 返回一个比较器按照value的自然顺序比较Map.Entry。
         */
        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
        }

        /**
         * 返回一个比较器,该比较器使用给定的比较器按值比较MapEntry。
         * 如果指定的比较器也是可序列化的,则返回的比较器是可序列化的。
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
        }

        /**
         * 返回一个比较器,该比较器使用给定的比较器按值比较MapEntry。
         * 如果指定的比较器也是可序列化的,则返回的比较器是可序列化的。
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
        }
    }

    // Comparison and hashing

    /**
     * 比较指定对象和this map。入股给定的对象也是一个map并且两个map都代表了相同的映射关系返回true
     * 两个map有相同的映射需要满足下面的条件:
     */
    boolean equals(Object o);

    /**
     * 返回此map的hash code。此map的hash code被定义为所有entry的hash code的和。
     */
    int hashCode();

    // 默认的方法

    /**
     * 根据指定的key返回value,如果没有那么返回指定的value
     */
    default V getOrDefault(Object key, V defaultValue) {
        V v;
        return (((v = get(key)) != null) || containsKey(key))
            ? v
            : defaultValue;
    }

    default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }

    /**
     * 如果指定的key没有和一个value建立映射(或者映射为null),那么就建立映射,否则返回已经有的值
     */
    default V putIfAbsent(K key, V value) {
        V v = get(key);
        if (v == null) {
            v = put(key, value);
        }

        return v;
    }

    /**
     * 移除指定key的entry,如果它当前有映射的值
     */
    default boolean remove(Object key, Object value) {
        Object curValue = get(key);
        if (!Objects.equals(curValue, value) ||
            (curValue == null && !containsKey(key))) {
            return false;
        }
        remove(key);
        return true;
    }
    /*其他方法不再说明,看源码注释即可*/
}


我们要注意的是,Map的hashCode的计算方法:

  • Map的hashCode是entrySet的hashCode
  • entrySet的hashCode是每一个entry的hashCode的求和
  • 每一个entry的hashCode是key和value异或的结果

二、AbstractMap


package java.util;
import java.util.Map.Entry;

/**
 * 这个抽象的map类,方便其他类继承并复用。
 * 为了事项一个无法改变的map,开发人员继承此类,并提供一个entrySet方法的实现,这个方法返回这个map的映射关系的set-view。
 * 
 * 
 * 通常,返回的集合将依次在AbstractSet之上实现。这个集合不应该支持add或remove方法,它的迭代器也不应该支持remove方法。
 *
 * 为了实现一个可修改的map,开发人员必须额外的重写pug方法(此方法会抛出UnsupportedOperationException异常),并且通过entrySet().iterator()返回的迭代器,必须额外实现remove方法。
 *
 * 开发人员通常应该提供一个空的构造函数。
 */

public abstract class AbstractMap<K,V> implements Map<K,V> {
    /**
     * 唯一的构造函数
     */
    protected AbstractMap() {
    }

    // 查询操作

    /**
     * 返回map的大小,其实就是entrySet的size.
     */
    public int size() {
        return entrySet().size();
    }

    /**
     * 判断map是否为空
     */
    public boolean isEmpty() {
        return size() == 0;
    }

    /**
     * 这个实现基于entrySet()的迭代实现。根据valud如果entry找到返回true,否则返回false
     */
    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;
    }

    /**
     * 同上,从entry中找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;
    }

    /**
     * 基于entrySet的迭代器实现,根据指定的key查找entry。如果找到返回entry的value。如果迭代被终止返回null。如果实现类要求线性时间那么可以重写此方法。
     */
    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;
    }


    // 修改操作

    /**
     * 此实现会抛出UnsupportedOperationException异常。
     */
    public V put(K key, V value) {
        throw new UnsupportedOperationException();
    }

    /**
     * 这个实现迭代基于entrySet()实现,查找指定key的entrySet。如果找到,获取他的值,使用iterator.remove()方法将此entrySet删除。如果迭代中断返回null。
     */
    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;
    }


    // Bulk Operations

    /**
     */
    public void putAll(Map<? extends K, ? extends V> m) {
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
    }
    public void clear() {
        entrySet().clear();
    }


    // 视图

    /**
     * 这些字段被初始化同包含一个适当的视图实例在第一次被需要时。
     * 这个视图是无状态的,所以没有必要创建超过一个。
     */
    transient Set<K>        keySet;
    transient Collection<V> values;

    /**
     * 此实现返回一个AbstractSet的子类。
     * 子类的迭代器方法返回一个包装对象基于map的entrySet()的迭代器。
     * size方法代表了这个map的size方法,contains方法代表这个map的containsKey方法
     * set在第一次这个方法调用时创建,然会一个所有子序列的响应
     */
    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;
    }

    /**
     */
    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;
    }

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


    // 比较和hashings

    /**
     * 同map接口的equals方法描述
     */
    public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map))
            return false;
        Map<?,?> m = (Map<?,?>) o;
        if (m.size() != size())
            return false;

        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

    /**
     * 同map的hashCode()方法描述
     */
    public int hashCode() {
        int h = 0;
        Iterator<Entry<K,V>> i = entrySet().iterator();
        while (i.hasNext())
            h += i.next().hashCode();
        return h;
    }

    /**
     * 返回一个代表这个map的string。这个string代表整个key-value映射的list,并且按照按照entrySet视图的iterator顺序。
     * 相邻的映射被","分割(逗号和空格)。
     */
    public String toString() {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (! i.hasNext())
            return "{}";

        StringBuilder sb = new StringBuilder();
        sb.append('{');
        for (;;) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key);
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value);
            if (! i.hasNext())
                return sb.append('}').toString();
            sb.append(',').append(' ');
        }
    }

    /**
     * 浅复制
     */
    protected Object clone() throws CloneNotSupportedException {
        AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
        result.keySet = null;
        result.values = null;
        return result;
    }

    /**
     * 
     */
    private static boolean eq(Object o1, Object o2) {
        return o1 == null ? o2 == null : o1.equals(o2);
    }

    /**
     * 说明:SimpleEntry和SimpleImmutableEntry是明显不相关的类,即使他们有共享相同的代码。
     */


    /**
     * 一个entry包含一个key和一个value.value可以通过setValue方法改变。
     * 这个类促进构建自定义map的实现。例如,通过Map.entrySet().toArray方法来返回一个SimpleEntry数组是很方便的。
     */
    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;

        /**
         * 创建一个entry代表一个指定的key和value的映射关系
         */
        public SimpleEntry(K key, V value) {
            this.key   = key;
            this.value = value;
        }

        /**
         * 创建一个entry表示了指定的相同的entry映射关系
         */
        public SimpleEntry(Entry<? extends K, ? extends V> entry) {
            this.key   = entry.getKey();
            this.value = entry.getValue();
        }

        /**
         * 返回与此entry对应的key
         */
        public K getKey() {
            return key;
        }

        /**
         * 返回与此entry对应的value
         */
        public V getValue() {
            return value;
        }

        /**
         * 用指定的value代替entry中的value
         */
        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        /**
         * 比较指定的对象和entry.
         * 同Map描述
         */
        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());
        }

        /**
         * 同map中的描述
         */
        public int hashCode() {
            return (key   == null ? 0 :   key.hashCode()) ^
                   (value == null ? 0 : value.hashCode());
        }

        public String toString() {
            return key + "=" + value;
        }

    }

    /**
     * 一个entry保持了不变的key和value。这个类不支持setValue方法。
     * 在返回键值映射的线程安全快照的方法中,这个类可能很方便。
     */
    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;

        /**
         * 生成一个entry代表一个指定key和value的映射关系。
         */
        public SimpleImmutableEntry(K key, V value) {
            this.key   = key;
            this.value = value;
        }

        /**
         * 根据指定的entry生成一个entry
         */
        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();
        }


        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());
        }

        public int hashCode() {
            return (key   == null ? 0 :   key.hashCode()) ^
                   (value == null ? 0 : value.hashCode());
        }

        public String toString() {
            return key + "=" + value;
        }

    }

}


--完--