Java 集合体系之 AbstractMap 源码分析

前言

AbstractMap 是一个实现了 Map 接口的抽象类,该类提供了 Map 接口的骨架实现,以最大限度的减少实现此接口所带来的工作量。

要实现一个不可修改的 Map,我们只需要扩展此类,并实现 entrySet() 方法(AbstractMap 唯一的抽象方法)即可,该方法返回存有 Map 映射关系的 Set 集合。通常,返回的 Set 又将在 AbstractSet 上实现。此 Set 不应该支持 add() 或 remove() 方法,其迭代器也不应该支持 remove() 方法。

要实现一个可修改的 Map,我们必须另外重写此类的 put 方法(否则将抛出 UnsupportedOperationException 异常),并且由 entrySet().iterator() 返回的迭代器也必须另外实现其 remove() 方法。

按照 Map 接口规范中的建议,我们通常应该提供一个 void(无参数)构造方法和 map 构造方法。

源码分析

构造方法

唯一的无参构造函数,用于子类构造函数的调用,通常是隐式的:

protected AbstractMap() {
}

成员变量

其成员变量有如下两个:

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

都是由 transient 关键字所修饰,表示在序列化时不保存。
并且都只是声明了,并没有被赋值。赋值将会在下面的 keySet() 与 values() 方法中操作。
– keySet:保存所有 key 的 Set 集合。
– values:保存所有 value 的 Collection 集合。

抽象方法

抽象方法就只有一个,返回保存 Map 中所有映射条目的 Set 集合:

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

实例方法

查询操作

返回集合的长度:

public int size() {
    return entrySet().size();
}

返回集合是否为空,为空时返回 true,否则返回 false:

public boolean isEmpty() {
    // 当集合中的元素个数为 0 时返回 true
    return size() == 0;
}

返回集合中是否存在指定的 value(支持 null),存在则返回 true,否则返回 false:

public boolean containsValue(Object value) {
    // 获取迭代器
    Iterator<Entry<K,V>> i = entrySet().iterator();
    // 循环遍历取出 value 与 指定的 value 进行比对,比对成功返回 true
    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;
        }
    }
    // 没有找到,返回 false
    return false;
}

返回集合中是否存在指定的 key(支持 null),存在则返回 true,否则返回 false:

public boolean containsKey(Object key) {
    // 获取迭代器
    Iterator<Map.Entry<K,V>> i = entrySet().iterator();
    // 循环遍历取出 key 与 指定的 key 进行比对,比对成功返回 true
    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;
        }
    }
    // 没有找到,返回 false
    return false;
}

获取指定 key 所映射的 value,没有找到,则返回 null:

public V get(Object key) {
    // 获取迭代器
    Iterator<Entry<K,V>> i = entrySet().iterator();
    // 循环遍历,当找到对应的 key 时取出与之相对应的 value
    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();
        }
    }
    // 没有找到,返回 null
    return null;
}

修改操作

将指定的 key 与 value 相关联(可选操作,意味着实现类可以实现该方法,也可以不实现,开头已经说过了,当想实现一个可修改的集合时可以重写修改操作的相关方法):

public V put(K key, V value) {
    // AbstractMap 的实现是直接抛出一个异常
    throw new UnsupportedOperationException();
}

删除指定 key 的映射条目,删除成功则返回指定 key 所映射的 value,删除失败,返回 null:

public V remove(Object key) {
    // 获取迭代器
    Iterator<Entry<K,V>> i = entrySet().iterator();
    // 定义一个映射条目变量,初始化为 null
    Entry<K,V> correctEntry = null;
    // 当 correntEntry 没有被赋值并集合中还有映射条目时
    // 就一直循环遍历集合找出与指定 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;
    // 当找到了指定 key 的映射条目,并且不为 null 时
    if (correctEntry !=null) {
        // 获取 key 所映射的 value,方法结束时返回该值
        oldValue = correctEntry.getValue();
        // 调用迭代器的删除方法,删除该映射条目
        // 注意迭代器的 remove() 方法实现也是抛出异常
        // 所以在实现一个可修改的集合时别忘了重写迭代器的 remove() 方法
        i.remove();
    }
    // 存在指定 key 的映射条目时返回其所映射的 value,否则返回 null
    return oldValue;
}

批量操作

将指定参数 Map 集合中的映射数据存储到当前 Map 中:

public void putAll(Map<? extends K, ? extends V> m) {
    // 遍历指定的 Map 集合的映射条目
    for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
        // 将映射中的 key、value 取出并存储到当前 Map中
        // 注意这里调用了 put() 方法,所以如果子类没有重写 put() 方法,那么该方法将会抛出异常
        put(e.getKey(), e.getValue());
}

清空当前 Map:

public void clear() {
    entrySet().clear();
}

视图

返回存储所有 key 的 Set 视图集合:

public Set<K> keySet() {
    Set<K> ks = keySet;
    // 当 key 的视图集合是空,则创建 AbstractSet 对象然后赋值
    if (ks == null) {
        ks = new AbstractSet<K>() {
            // AbstractSet 是一个抽象类,于是需要实现其抽象方法
            public Iterator<K> iterator() {
                // 返回的迭代器方法都是调用的 enterySet() 的迭代器实现
                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();
                    }
                };
            }
            // 其他方法也都是调用的当前抽象类 AbstractMap 的方法实现
            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;
    }
    // 返回 key 的 Set 视图集合
    return ks;
}

返回存储所有 value 的 Collection 视图集合:

public Collection<V> values() {
    // 该方法的实现同 keySet() 方法
    // 只不过由 Set 的 AbstractSet 对象实例,变为了 Collection 的 AbstractCollection 对象实例。
    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;
}

比较和散列

比较指定的对象是否与当前 Map相等:

public boolean equals(Object o) {
    // 比较地址值相等,直接返回 true
    if (o == this)
        return true;
    // 比较当指定对象不是 Map 或其实现类的实例,返回 false
    if (!(o instanceof Map))
        return false;
    // 强转为 map
    Map<?,?> m = (Map<?,?>) o;
    // 长度和当前 Map不一致,返回 false
    if (m.size() != size())
        return false;

    try {
        // 获取当前 Map的迭代器
        Iterator<Entry<K,V>> i = entrySet().iterator();
        // 遍历映射条目
        while (i.hasNext()) {
            // 获取 value 与指定 map 对象的 value 进行比较,不相等则返回 false 
            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;
    }
    // 当以上所有校验比对都通过了,那么返回 true
    return true;
}

返回当前 Map 的 hashCode:

public int hashCode() {
    int h = 0;
    Iterator<Entry<K,V>> i = entrySet().iterator();
    while (i.hasNext())
        // AbstractMap 的 hashCode 计算
        // 是其每个映射条目的 hashCode 的总和
        h += i.next().hashCode();
    return h;
}

其他方法

返回当前 Map 的字符串表示形式:

public String toString() {
    // 获取迭代器
    Iterator<Entry<K,V>> i = entrySet().iterator();
    // 没有数据时,直接返回:{}
    if (! i.hasNext())
        return "{}";
    // 创建 StringBuilder 对象,用于拼接字符串
    StringBuilder sb = new StringBuilder();
    // 循环开始前,拼接开始括号: {
    sb.append('{');
    for (;;) {
        // 获取映射条目的 key、value
        Entry<K,V> e = i.next();
        K key = e.getKey();
        V value = e.getValue();
        // 当 key 或者 value 是当前 Map 时,拼接 (this Map),否则拼接其 key、value
        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 实例的浅拷贝(键和值本身不被克隆):

protected Object clone() throws CloneNotSupportedException {
    // 调用 Native 方法
    AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
    // 将存储 key、value 的集合置为 null
    result.keySet = null;
    result.values = null;
    return result;
}

私有静态方法,给 SimpleEntry 和 SimpleImmutableEntry 内部类用的。
用于检查给定的两个对象是否相等(包括 null):

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

SimpleEntry

Map.Entry 接口的实现类,从 1.6 开始提供。
保存 key 和 value 映射的条目,在该内部类中其 value 可以用 setValue() 方法进行更改:

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;

    /** * 创建指定 key、value 的映射条目。 */
    public SimpleEntry(K key, V value) {
        this.key   = key;
        this.value = value;
    }

    /** * 从指定映射条目中获取的 key、value 来创建映射条目。 */
    public SimpleEntry(Entry<? extends K, ? extends V> entry) {
        this.key   = entry.getKey();
        this.value = entry.getValue();
    }

    /** * 获取 key */
    public K getKey() {
        return key;
    }

    /** * 获取 value */
    public V getValue() {
        return value;
    }

    /** * 设置新的 value 值,并返回旧的 value 值。 */
    public V setValue(V value) {
        V oldValue = this.value;
        this.value = value;
        return oldValue;
    }

    /** * 将指定的对象与当前映射条目进行比对,比对成功返回 true,否则返回 false。 */
    public boolean equals(Object o) {
        // 如果指定对象不是 Map.Entry 接口的实现类则直接返回 false
        if (!(o instanceof Map.Entry))
            return false;
        // 强转为 Map.Entry
        Map.Entry<?,?> e = (Map.Entry<?,?>)o;
        // 使用 eq() 静态方法对 key 与 value 进行比对
        return eq(key, e.getKey()) && eq(value, e.getValue());
    }

    /** * 返回映射条目的 hasCode。 */
    public int hashCode() {
        // hasCode 的计算是根据 key 与 value 的 hasCode 来的
        return (key   == null ? 0 :   key.hashCode()) ^
               (value == null ? 0 : value.hashCode());
    }

    /** * 返回映射条目的字符串表现形式。 */
    public String toString() {
        return key + "=" + value;
    }

}

SimpleImmutableEntry

顾名思义,不可变的 SimpleEntry。该内部类同样是 Map.Entry 接口的实现类,从 1.6 开始提供。
与 SimpleEntry 唯一的不同就是,其 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;

    public SimpleImmutableEntry(K key, V value) {
        this.key   = key;
        this.value = value;
    }

    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) {
        // look here
        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;
    }
}

到这,AbstractMap 抽象类的源码就看完了。最后再来总结一下。

总结

AbstractMap 作为实现 Map 接口的抽象类,其作用及目的就是简化实现 Map 接口所带来的工作量。像常用的 TreeMap、HashMap 等都是继承自它。我们在自己设计框架的时候,其实也是可以采用这种设计思想的。

    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/Airsaid/article/details/51178444
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞