前言
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 等都是继承自它。我们在自己设计框架的时候,其实也是可以采用这种设计思想的。