java容器 抽象类AbstractMap源码分析

目录

 

简介

查询 size,isEmpty,containsKey,containsValue

增删改查 get,put,remove

批量操作 putAll,clear

两个字段 keySet,values

keySet,values方法的内部类

通用方法 equals,hashCode,toString,clone,eq

内部类 SimpleEntry

内部类  SimpleImmutableEntry


简介

/**
 * 

这个类提供了Map接口的骨架实现,最小化了实现这个接口的努力。 * *

为了实现一个不可更改的map,编程者只需要继承这个类, * 并且提供entrySet方法的实现,entrySet方法返回map的映射的set视图。 * 通常,返回的set会在AbstractSet上实现。 * 这个set不应该支持add或者remove方法,它的迭代器不应该支持remove方法。 * *

为了实现一个可更改的map,编程者需要额外覆盖这个类的put方法(这个方法会抛出UnsupportedOperationException) * entrySet().iterator()返回的迭代器必须额外实现remove方法。 * *

编程者应该通常提供一个无参构造器和参数为map的构造器,根据Map接口规范的建议。 * *

这个类的每个非抽象方法的文档详细地描述了它的实现。 * 如果实现的map要实现更有效的方法,这些方法可以被覆盖。 * * @param the type of keys maintained by this map * @param the type of mapped values * * @author Josh Bloch * @author Neal Gafter * @see Map * @see Collection * @since 1.2 */ public abstract class AbstractMap implements Map

java容器 抽象类AbstractMap源码分析_第1张图片

java容器 抽象类AbstractMap源码分析_第2张图片

 

查询 size,isEmpty,containsKey,containsValue

    /**
     * Sole constructor.  (For invocation by subclass constructors, typically
     * implicit.)
     */
    protected AbstractMap() {
    }

    // Query Operations

    /**
     * {@inheritDoc}
     *
     * 

实现返回 entrySet().size(). */ public int size() { return entrySet().size(); } /** * {@inheritDoc} * *

实现返回 size() == 0. */ public boolean isEmpty() { return size() == 0; } /** * {@inheritDoc} * *

这个实现迭代entrySet(),查找有着指定value的entry。 * 如果一旦有entry被找到,返回true。 * 如果迭代以没有找到entry停止,返回false。 * 注意:这个实现需要与map的大小的线性相关的时间。 * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public boolean containsValue(Object value) { Iterator> i = entrySet().iterator(); // 对entrySet迭代 if (value==null) { while (i.hasNext()) { Entry e = i.next(); if (e.getValue()==null) return true; } } else { while (i.hasNext()) { Entry e = i.next(); if (value.equals(e.getValue())) return true; } } return false; } /** * {@inheritDoc} * *

这个实现迭代entrySet(),查找有着指定key的entry。 * 如果一旦有entry被找到,返回true。 * 如果迭代以没有找到entry停止,返回false。 * 注意:这个实现需要与map的大小的线性相关的时间。 *

许多实现会覆盖这个方法。 * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public boolean containsKey(Object key) { Iterator> i = entrySet().iterator(); if (key==null) { while (i.hasNext()) { Entry e = i.next(); if (e.getKey()==null) return true; } } else { while (i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) return true; } } return false; }

增删改查 get,put,remove

    /**
     * {@inheritDoc}
     *
     * 

这个实现迭代entrySet(),查找有着指定key的entry。 * 如果一旦有entry被找到,返回entry的value。 * 如果迭代以没有找到entry停止,返回null。 * 注意:这个实现需要与map的大小的线性相关的时间。 *

许多实现会覆盖这个方法。 * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public V get(Object key) { Iterator> i = entrySet().iterator(); if (key==null) { while (i.hasNext()) { Entry e = i.next(); if (e.getKey()==null) return e.getValue(); } } else { while (i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) return e.getValue(); } } return null; } // Modification Operations /** * {@inheritDoc} * * @implSpec * This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ public V put(K key, V value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * *

这个实现迭代entrySet(),查找有着指定key的entry。 * 如果一旦有entry被找到,它的value通过entry的getValue方法得到, * entry通过Iterator的remove方法被删除,并将存储的value返回。 * 如果迭代以没有找到entry停止,返回null。 * 注意:这个实现需要与map的大小的线性相关的时间。 *

许多实现会覆盖这个方法。 * *

注意:这个实现会抛出UnsupportedOperationException, * 如果entrySet的Iterator没有支持remove方法,并且map包含指定key对应的映射。 * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public V remove(Object key) { Iterator> i = entrySet().iterator(); Entry correctEntry = null; if (key==null) { while (correctEntry==null && i.hasNext()) { Entry e = i.next(); if (e.getKey()==null) correctEntry = e; } } else { while (correctEntry==null && i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) // 找到对应entry correctEntry = e; } } V oldValue = null; if (correctEntry !=null) { oldValue = correctEntry.getValue(); i.remove(); // 通过Iterator的remove方法删除 } return oldValue; }

批量操作 putAll,clear

    // Bulk Operations

    /**
     * {@inheritDoc}
     * 
     * 

这个实现迭代entrySet(),对迭代过程中返回的每个entry调用map的put操作 * *

注意:这个实现会抛出UnsupportedOperationException, * 如果这个map不支持put操作,并且指定map非空。 * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ public void putAll(Map m) { for (Map.Entry e : m.entrySet()) // 对m.entrySet()迭代 put(e.getKey(), e.getValue()); // 在这个map逐个放入 } /** * {@inheritDoc} * *

这个实现调用 entrySet().clear(). * *

注意:这个实现会抛出UnsupportedOperationException, * 如果这个entrySet不支持clear操作 * * @throws UnsupportedOperationException {@inheritDoc} */ public void clear() { entrySet().clear(); }

两个字段 keySet,values

    /**
     * 在第一次请求改视图的时候,下面的每个字段会被初始化,来拥有一个适当的视图的实例。
     *
     * 

因为访问这些字段没有执行同步,所以希望java.util.Map的使用这些字段的视图类, * 没有非final的字段(或者除了outer,this之外的任何字段都是final的)。 * 遵守这个规则会让在这些字段上的竞争变得良性。 * *

还有一点也是有必要的:实现只能读取这个字段仅仅一次,如: *

 {@code
     * public Set keySet() {
     *   Set ks = keySet;  // single racy read
     *   if (ks == null) {
     *     ks = new KeySet();
     *     keySet = ks;
     *   }
     *   return ks;
     * }
     *}
*/ transient Set keySet; transient Collection values;

keySet,values方法的内部类

    /**
     * {@inheritDoc}
     *
     * 

实现返回一个AbstractSet的子类。 * 子类的Iterator方法返回了基于这个map的entrySet的迭代器的一个包装对象。 * size方法对应map的size方法,contains方法对应map的containsKey方法。 * *

这个set在这个方法被第一次调用时,被创建,并且对接下来所有的调用,返回这个set。 * 不会执行同步,所以有很小的可能性,多次调用这个方法不会返回同一个set。 */ public Set keySet() { Set ks = keySet; if (ks == null) { // keySet没有被创建,才创建,单例模式 ks = new AbstractSet() { public Iterator iterator() { return new Iterator() { private Iterator> i = entrySet().iterator(); // 根据entrySet的Iterator public boolean hasNext() { return i.hasNext(); } public K next() { return i.next().getKey(); // entrySet的getkey } public void remove() { i.remove(); // 删除entrySet } }; } public int size() { return AbstractMap.this.size(); // map自己的size } public boolean isEmpty() { return AbstractMap.this.isEmpty(); // map自己的isEmpty } public void clear() { AbstractMap.this.clear(); // map自己的clear } public boolean contains(Object k) { return AbstractMap.this.containsKey(k); // map自己的containsKey } }; keySet = ks; // 创建后,赋值给keySet } return ks; } /** * {@inheritDoc} * *

实现返回一个AbstractCollection的子类。 * 子类的Iterator方法返回了基于这个map的entrySet的迭代器的一个包装对象。 * size方法对应map的size方法,contains方法对应map的containsValue方法。 * *

这个collection在这个方法被第一次调用时,被创建,并且对接下来所有的调用,返回这个collection。 * 不会执行同步,所以有很小的可能性,多次调用这个方法不会返回同一个collection。 */ public Collection values() { Collection vals = values; if (vals == null) { vals = new AbstractCollection() { public Iterator iterator() { return new Iterator() { private Iterator> 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> entrySet();

通用方法 equals,hashCode,toString,clone,eq

    // Comparison and hashing

    /**
     * 

将指定对象与这个map进行相等性的比较。 * 如果指定对象也是一个map,两个map代表相同的映射,返回true。 * 更正式地,两个map m1和m2代表相同的映射,如果m1.entrySet().equals(m2.entrySet())。 * 这保证equals方法在不同的Map接口的实现间工作正常。 * *

这个实现一开始检查指定对象是否是这个map自己,如果是,返回true。 * 然后,检查指定对象是否是一个大小与这个map的大小相同的map,如果不是,返回false。 * 如果是,迭代这个map的entrySet集合,检查指定map是否包含这个map包含的每个映射。 * 如果指定map不包含这样的一个映射,返回false。 * 如果迭代结束,返回true。 * * @param o object to be compared for equality with this map * @return true if the specified object is equal to this map */ 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> i = entrySet().iterator(); // 对自己迭代 while (i.hasNext()) { Entry 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))) // 自己的value与 m.get(key)是否相同 return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; } /** * 返回map的hashcode。 * map的hashcode根据map的entrySet()视图的每个entry的hashcode的和定义。 * 这保证对于任意两个map m1和m2,m1.equals(m2)代表m1.hashCode()==m2.hashCode(), * 根据Object.hashCode的通常约定。 * *

这个实现迭代了entrySet,对每个entry,调用hashcode方法,将结果加起来 * * @return the hash code value for this map * @see Map.Entry#hashCode() * @see Object#equals(Object) * @see Set#equals(Object) */ public int hashCode() { int h = 0; Iterator> i = entrySet().iterator(); // 对entrySet迭代 while (i.hasNext()) h += i.next().hashCode(); // 调用entry自己的hashcode,加起来 return h; } /** * 返回这个map的字符串表示。 * 字符串表示由一个key-value映射的列表构成,顺序为entrySet迭代器返回的顺序,以大括号{}包围。 * 相邻的映射以字符逗号和空格, 分隔。 * 每个key-value映射以key然后是等号= 然后是关联的value。 * key和value被转换成字符串,通过String.valueOf()方法 * * @return a string representation of this map */ public String toString() { Iterator> i = entrySet().iterator(); if (! i.hasNext()) return "{}"; StringBuilder sb = new StringBuilder(); sb.append('{'); // 以大括号进行包围 for (;;) { Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); // 对entrySet进行迭代 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(' '); } } /** * 返回这个AbstractMap实例的浅复制:key和values它们自己没有被复制。 * * @return a shallow copy of this map */ protected Object clone() throws CloneNotSupportedException { AbstractMap result = (AbstractMap)super.clone(); result.keySet = null; result.values = null; return result; } /** * 为了SimpleEntry和SimpleImmutableEntry的工具方法。 * 对于相等性的测试,检查null值。 * * NB: Do not replace with Object.equals until JDK-8015417 is resolved. */ private static boolean eq(Object o1, Object o2) { return o1 == null ? o2 == null : o1.equals(o2); }

内部类 SimpleEntry

    /**
     * 实现注意:SimpleEntry和SimpleImmutableEntry在不相关的类间是不同的,
     * 即使它们共享一些代码。
     * 因为你不能在一个子类中,增加或者减去字段的final修饰符,
     * 所以它们不能共享形式,并且重复的代码太少了,不足以公开共同的抽象类
     *
     */    

    /**
     * 一个entry保存一个key和value。
     * value可以用setValue方法改变。
     * 这个类简化了自定义的map实现的过程。
     * 例如,这可以在Map.entrySet().toArray方法返回SimpleEntry实例的数组,比较方便。
     *
     * @param 
     * @param 
     */
    public static class SimpleEntry
        implements Entry, java.io.Serializable
    {
        private static final long serialVersionUID = -8499721149061103585L;

        private final K key; // key为final
        private V value; // value可变

        /**
         * 使用指定的key和value创建一个entry,代表一个映射
         *
         * @param key the key represented by this entry
         * @param value the value represented by this entry
         */
        public SimpleEntry(K key, V value) {
            this.key   = key;
            this.value = value;
        }

        /**
         * 创建一个entry,代表与指定entry相同的映射。
         *
         * @param entry the entry to copy
         */
        public SimpleEntry(Entry entry) {
            this.key   = entry.getKey();
            this.value = entry.getValue();
        }

        /**
         * 返回这个entry对应的key
         *
         * @return the key corresponding to this entry
         */
        public K getKey() {
            return key;
        }

        /**
         * 返回这个entry对应的value。
         *
         * @return the value corresponding to this entry
         */
        public V getValue() {
            return value;
        }

        /**
         * 将entry的value替代为指定的value
         *
         * @param value new value to be stored in this entry
         * @return the old value corresponding to the entry
         */
        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        /**
         * 将指定对象与这个entry进行相等性的比较。
         * 如果给定的对象也是一个map的entry,两个entry代表同样的映射,返回true。
         * 更正式地,两个entry e1和e2代表同样的映射,如果:
         * 
         *   (e1.getKey()==null ?
         *    e2.getKey()==null :
         *    e1.getKey().equals(e2.getKey()))
         *   &&
         *   (e1.getValue()==null ?
         *    e2.getValue()==null :
         *    e1.getValue().equals(e2.getValue()))
* 这保证equals方法在不同的Map.Entry接口的实现间,工作正常。 * * @param o object to be compared for equality with this map entry * @return {@code true} if the specified object is equal to this map * entry * @see #hashCode */ 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()); // 两者的key和value都相同 } /** * 返回这个map entry的hashcode。hashcode安装如下定义(key和value的hashcode进行亦或): *
         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
         * 
* 这保证e1.equals(e2)代表e1.hashCode()==e2.hashCode(), * 对于任何两个entry e1和e2,按照Object的hashCode的要求 * * @return the hash code value for this map entry * @see #equals */ public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } /** * 返回这个entry的字符串表示。 * 字符串表示先是key的字符串表示,然后是等号=,然后是value的字符串表示 * * @return a String representation of this map entry */ public String toString() { return key + "=" + value; } }

内部类  SimpleImmutableEntry

    /**
     * 一个entry保存不可更改的一个key和value。
     * 这个类不支持setValue操作
     * 这个类对返回线程安全的key-value映射的快照的方法,十分方便。
     *
     * @since 1.6
     */
    public static class SimpleImmutableEntry
        implements Entry, java.io.Serializable
    {
        private static final long serialVersionUID = 7138329143949025153L;

        private final K key;
        private final V value; // 都是final的

        /**
         * Creates an entry representing a mapping from the specified
         * key to the specified value.
         *
         * @param key the key represented by this entry
         * @param value the value represented by this entry
         */
        public SimpleImmutableEntry(K key, V value) {
            this.key   = key;
            this.value = value;
        }

        /**
         * Creates an entry representing the same mapping as the
         * specified entry.
         *
         * @param entry the entry to copy
         */
        public SimpleImmutableEntry(Entry entry) {
            this.key   = entry.getKey();
            this.value = entry.getValue();
        }

        /**
         * Returns the key corresponding to this entry.
         *
         * @return the key corresponding to this entry
         */
        public K getKey() {
            return key;
        }

        /**
         * Returns the value corresponding to this entry.
         *
         * @return the value corresponding to this entry
         */
        public V getValue() {
            return value;
        }

        /**
         * Replaces the value corresponding to this entry with the specified
         * value (optional operation).  This implementation simply throws
         * UnsupportedOperationException, as this class implements
         * an immutable map entry.
         *
         * @param value new value to be stored in this entry
         * @return (Does not return)
         * @throws UnsupportedOperationException always
         */
        public V setValue(V value) {
            throw new UnsupportedOperationException(); // 不支持setValue
        }

        /**
         * Compares the specified object with this entry for equality.
         * Returns {@code true} if the given object is also a map entry and
         * the two entries represent the same mapping.  More formally, two
         * entries {@code e1} and {@code e2} represent the same mapping
         * if
         *   (e1.getKey()==null ?
         *    e2.getKey()==null :
         *    e1.getKey().equals(e2.getKey()))
         *   &&
         *   (e1.getValue()==null ?
         *    e2.getValue()==null :
         *    e1.getValue().equals(e2.getValue()))
* This ensures that the {@code equals} method works properly across * different implementations of the {@code Map.Entry} interface. * * @param o object to be compared for equality with this map entry * @return {@code true} if the specified object is equal to this map * entry * @see #hashCode */ 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()); } /** * Returns the hash code value for this map entry. The hash code * of a map entry {@code e} is defined to be:
         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
         *   (e.getValue()==null ? 0 : e.getValue().hashCode())
* This ensures that {@code e1.equals(e2)} implies that * {@code e1.hashCode()==e2.hashCode()} for any two Entries * {@code e1} and {@code e2}, as required by the general * contract of {@link Object#hashCode}. * * @return the hash code value for this map entry * @see #equals */ public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } /** * Returns a String representation of this map entry. This * implementation returns the string representation of this * entry's key followed by the equals character ("=") * followed by the string representation of this entry's value. * * @return a String representation of this map entry */ public String toString() { return key + "=" + value; } }

 

 

你可能感兴趣的:(java容器,源码分析)