Java集合类源码解析:AbstractMap

Posted 鄙人薛某

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于Java集合类源码解析:AbstractMap的主要内容,如果未能解决你的问题,请参考以下文章

Java 集合Hashtable源码深入解析

java集合HashMap源码解析(基于JDK1.8)

java集合HashMap源码解析(基于JDK1.8)

java源码 -- AbstractMap

HashMap 源码解析之使用构造以及计算容量

JAVA 集合类(java.util)源码阅读笔记------WeakHashMap