Java容器解析系列(10) Map AbstractMap 详解

时间:2021-01-01 13:25:21

前面介绍了ListQueue相关源码,这篇开始,我们先来学习一种java集合中的除Collection外的另一个分支------Map,这一分支的类图结构如下:

Java容器解析系列(10) Map AbstractMap 详解

这里为什么不先介绍Set相关:因为很多Set实现类是通过对应的Map来实现,使用Map中key不能重复的特性,往Set中add元素的本质就是Map的put(),这里先介绍Map,后续介绍Set的时候再做具体介绍

首先,我们来看Map接口:

/**
Map将key映射到value(存储键值对);
一个map不能存在重复的key;
一个key最多可以映射到1个value;
这个接口用来替换Dictionary抽象类;
* @since 1.2
*/
public interface Map<K,V> {
// Query Operations
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value); // 按照指定键获得相对应的值;
// 如果不能存在指定键值对则返回null;
V get(Object key); // Modification Operations // 可选操作;添加指定键值对
V put(K key, V value); // 可选操作;
// 移除指定键值对;
// 返回移除前key对应的value;
V remove(Object key); // Bulk Operations void putAll(Map<? extends K, ? extends V> m);
void clear(); // Views // 返回Map中所有key的视图
Set<K> keySet();
// 返回Map中所有value的视图
Collection<V> values();
// 返回Map中所有的Entry的视图,也即key-value的视图
Set<Map.Entry<K, V>> entrySet(); // 一个Entry就是一个键值对;
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
} // Comparison and hashing boolean equals(Object o);
int hashCode(); }

和所有集合接口一样,Map接口主要是定义键值对相关的增删改查的操作,考虑到实现不可修改的Map的实现,其中增加(其实也包括修改)和删除都是可选操作.

Map接口中必须实现的方法主要是围绕着查找遍历Map:

Map中提供了3种遍历方式:

  1. 使用keySet()获取所有key的集合,然后用集合里面的可以获取所有value;
  2. 使用values() 获取所有value的集合;
  3. 使用entrySet()获取所有key-value的集合;

    其使用代码案例如下:
    Set set = map.keySet();
for (Object key : set) {
System.out.println(map.get(key));
}
    Collection values = map.values();
Iterator iterator = values.iterator();
while (iterator.hasNext()){
System.out.println("value " + iterator.next());
}
    Set entrySet = map.entrySet();
for (Object o : entrySet) {
Map.Entry entry = (Map.Entry) o;
System.out.println(entry); //key=value
System.out.println(entry.getKey() + " / " + entry.getValue());
}

和之前介绍的集合类一样,Map相关也提供了一个AbstractMap抽象类,提供Map的骨架实现,其所有功能都是通过entrySet()来实现,下面是其源代码:

为了简略篇幅,这里只列出部分具代表性的方法源码,具体可以参考jdk源码

/**
* 提供Map接口的骨架实现;
* 如果要实现一个不可修改的map,只需要继承该类,并实现entrySet方法,其返回的Set应不可修改;
* @since 1.2
*/
public abstract class AbstractMap<K, V> implements Map<K, V> { protected AbstractMap() {} // Query Operations public int size() {
return entrySet().size();
} public boolean isEmpty() {
return size() == 0;
} public boolean containsValue(Object value) {
// ...
} public boolean containsKey(Object key) {
// ...
} // 通过entrySet()来实现,其实所有的方法都是通过entrySet()来实现
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;
} // Modification Operations // 默认不允许添加键值对
public V put(K key, V value) {
throw new UnsupportedOperationException();
} // 通过entrySet()实现,如果entrySet()不支持移除,其remove()会抛出UnsupportedOperationException
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();
} // Views transient volatile Set<K> keySet = null;
transient volatile Collection<V> values = null; public Set<K> keySet() {
// ...
} public Collection<V> values() {
// ...
} // entrySet()仍然为抽象方法,待子类实现
public abstract Set<Entry<K, V>> entrySet(); // Comparison and hashing public boolean equals(Object o) {
// ...
} public int hashCode() {
// ...
} public String toString() {
// ...
} protected Object clone() throws CloneNotSupportedException {
// ...
} private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}

除了上面的之外,在jdk1.6之后,AbstractMap还提供了SimpleEntrySimpleImmutableEntry两个静态内部类,其均实现了Map.Entry接口,两者的唯一区别为SimpleImmutableEntry不支持修改key对应的value,其setValue()如下:

public V setValue(V value) {
throw new UnsupportedOperationException();
}

SimpleEntry的源代码如下,没有什么需要特别讲解的:

/**
* @since 1.6
*/
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; public SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
} public SimpleEntry(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) {
V oldValue = this.value;
this.value = value;
return oldValue;
} 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;
} }