Java集合系列(九)-Map、AbstractMap等
Map是一种key、value类型是数据结构,key不允许有重复,不同的Map实现对null有不同的要求。
在Java中,Map的类结构如下图所示:
一、Map源码
我们先看Map的源码。
package java.util;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;
/**
* 是一种映射keys到values的对象。一个map中不允许包含重复的keys,每个key最多映射一个值。
* 这个接口代替了Dictionary类,Dictionary是一个抽象类而不是一个接口。
*
* Map接口提供了三个集合视图,这些视图允许将映射的内容看作键集、值集或键值映射集。
* 一个map的顺序是基于map返回元素的集合迭代器的顺序定义的。一些map比如TreeMap保证了元素
* 的顺序,其他的比如hashMap并没有保证。
*
* 所有一般的map实现类应该提供两个标准的构造函数:无参的,和以Map作为参数的,以map作为参数的
* 生产一个新的map和参数有着相同的key和value.
* 一些Map实现对他们包含的key和value有限制。比如有的map实现禁止null的Key和value,,一些限制他们呢key的类型和。 尝试去插入一个不合格的key或者value将会抛出一个为检查异常,典型的异常有
* NullPointerException或者ClassCastException。
* 如果尝试去查询已经存在的被限制的key或valud可能会抛出异常或者返回false,有些实现将禁止前者
* 而有些实现禁止后者。
*/
public interface Map<K,V> {
// 查询操作
/**
* 返回这个map种key-value映射关系的数量。如果map包含超过Integer.MAX_VALUE,那么返回
* Integer.MAX_VALUE
*/
int size();
/**
* 如果这个map中有元素返回true
*/
boolean isEmpty();
/**
* 如果这个map包含指定的key返回true.
*
*/
boolean containsKey(Object key);
/**
* 如果这个map中包含一个或者更多指定的value那么返回true
* 对于map接口的大多数实现,此操作可能需要映射大小的时间线性关系。
*/
boolean containsValue(Object value);
/**
* 返回指定key对应的value,如果没有的话返回null
* 如果该映射允许null值,则返回null值并不一定表示该映射不包含键的映射;
* 也有可能映射显式地将键映射为null。containsKey操作可以用来区分这两种情况。
*/
V get(Object key);
// 修改操作
/**
* 将指定的key和value联系到一起,如果map中之前包含了指定key,那么旧值将会被替代
* 当且仅当containsKey(对象m.containsKey(k)将返回true)返回true时,映射m将包含键k的映射。
*/
V put(K key, V value);
/**
* 根据指定的key移除这个map中的key-value映射如果存在这样的映射的话。
* 返回值是被删除的value,或者null如果没有对应的映射的话。
* 一旦调用此方法之后,此map中将不再包含指定的对应关系。
*/
V remove(Object key);
// 容量操作
/**
* 复制所有的映射从指定的map关系中到this map中。
*/
void putAll(Map<? extends K, ? extends V> m);
/**
* 移除this map中所有的映射关系,调用此方法后map中将会是空的。
*/
void clear();
// Views
/**
* 返回this map中的key的set视图。
* set基于map,如果map改变了那set也跟着改变
*/
Set<K> keySet();
/**
* 返回map中value的集合。
*/
Collection<V> values();
/**
* 返回一个此map的EntrySet
*/
Set<Map.Entry<K, V>> entrySet();
/**
* 一个map的entry(key-value对)类。Map.entrySet方法返回此类的元素的map集合视图。
* 只有一种方式获取map的entry引用就是迭代器。
* 这些Map.Entry对象只在迭代期间是有效的。
*/
interface Entry<K,V> {
/**
* 返回entry中的key
*/
K getKey();
/**
* 返回entry中的value
*/
V getValue();
/**
* 代替这个entry中对应的值。
*/
V setValue(V value);
/**
* 比较指定的对象与this entry。
* 返回true如果指定的对象也是this entry并且两个entry代表相同的映射。
* 通常,如果e1和e2有相同的映射要满足下面的关系比较:
* if
* (e1.getKey()==null ?
* e2.getKey()==null : e1.getKey().equals(e2.getKey()))
* (e1.getValue()==null ?
* e2.getValue()==null : e1.getValue().equals(e2.getValue()))
*/
boolean equals(Object o);
/**
* 返回此map entry的hashCode值。一个map entry的hashCode值按照如下定义:
* (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
* (e.getValue()==null ? 0 : e.getValue().hashCode())
* 这个确保e1.equals(e2) 意味着 e1.hashCode()==e2.hashCode()。
*/
int hashCode();
/**
* 返回一个比较器按照key的自然顺序比较Map.Entry。
*/
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
/**
* 返回一个比较器按照value的自然顺序比较Map.Entry。
*/
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
/**
* 返回一个比较器,该比较器使用给定的比较器按值比较MapEntry。
* 如果指定的比较器也是可序列化的,则返回的比较器是可序列化的。
*/
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
/**
* 返回一个比较器,该比较器使用给定的比较器按值比较MapEntry。
* 如果指定的比较器也是可序列化的,则返回的比较器是可序列化的。
*/
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
}
// Comparison and hashing
/**
* 比较指定对象和this map。入股给定的对象也是一个map并且两个map都代表了相同的映射关系返回true
* 两个map有相同的映射需要满足下面的条件:
*/
boolean equals(Object o);
/**
* 返回此map的hash code。此map的hash code被定义为所有entry的hash code的和。
*/
int hashCode();
// 默认的方法
/**
* 根据指定的key返回value,如果没有那么返回指定的value
*/
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
/**
* 如果指定的key没有和一个value建立映射(或者映射为null),那么就建立映射,否则返回已经有的值
*/
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
/**
* 移除指定key的entry,如果它当前有映射的值
*/
default boolean remove(Object key, Object value) {
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
remove(key);
return true;
}
/*其他方法不再说明,看源码注释即可*/
}
我们要注意的是,Map的hashCode的计算方法:
- Map的hashCode是entrySet的hashCode
- entrySet的hashCode是每一个entry的hashCode的求和
- 每一个entry的hashCode是key和value异或的结果
二、AbstractMap
package java.util;
import java.util.Map.Entry;
/**
* 这个抽象的map类,方便其他类继承并复用。
* 为了事项一个无法改变的map,开发人员继承此类,并提供一个entrySet方法的实现,这个方法返回这个map的映射关系的set-view。
*
*
* 通常,返回的集合将依次在AbstractSet之上实现。这个集合不应该支持add或remove方法,它的迭代器也不应该支持remove方法。
*
* 为了实现一个可修改的map,开发人员必须额外的重写pug方法(此方法会抛出UnsupportedOperationException异常),并且通过entrySet().iterator()返回的迭代器,必须额外实现remove方法。
*
* 开发人员通常应该提供一个空的构造函数。
*/
public abstract class AbstractMap<K,V> implements Map<K,V> {
/**
* 唯一的构造函数
*/
protected AbstractMap() {
}
// 查询操作
/**
* 返回map的大小,其实就是entrySet的size.
*/
public int size() {
return entrySet().size();
}
/**
* 判断map是否为空
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* 这个实现基于entrySet()的迭代实现。根据valud如果entry找到返回true,否则返回false
*/
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;
}
/**
* 同上,从entry中找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;
}
/**
* 基于entrySet的迭代器实现,根据指定的key查找entry。如果找到返回entry的value。如果迭代被终止返回null。如果实现类要求线性时间那么可以重写此方法。
*/
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;
}
// 修改操作
/**
* 此实现会抛出UnsupportedOperationException异常。
*/
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
/**
* 这个实现迭代基于entrySet()实现,查找指定key的entrySet。如果找到,获取他的值,使用iterator.remove()方法将此entrySet删除。如果迭代中断返回null。
*/
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();
}
// 视图
/**
* 这些字段被初始化同包含一个适当的视图实例在第一次被需要时。
* 这个视图是无状态的,所以没有必要创建超过一个。
*/
transient Set<K> keySet;
transient Collection<V> values;
/**
* 此实现返回一个AbstractSet的子类。
* 子类的迭代器方法返回一个包装对象基于map的entrySet()的迭代器。
* size方法代表了这个map的size方法,contains方法代表这个map的containsKey方法
* set在第一次这个方法调用时创建,然会一个所有子序列的响应
*/
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = 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);
}
};
keySet = ks;
}
return ks;
}
/**
*/
public Collection<V> values() {
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;
}
public abstract Set<Entry<K,V>> entrySet();
// 比较和hashings
/**
* 同map接口的equals方法描述
*/
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<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
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;
}
return true;
}
/**
* 同map的hashCode()方法描述
*/
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
/**
* 返回一个代表这个map的string。这个string代表整个key-value映射的list,并且按照按照entrySet视图的iterator顺序。
* 相邻的映射被","分割(逗号和空格)。
*/
public String toString() {
Iterator<Entry<K,V>> i = entrySet().iterator();
if (! i.hasNext())
return "{}";
StringBuilder sb = new StringBuilder();
sb.append('{');
for (;;) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
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(' ');
}
}
/**
* 浅复制
*/
protected Object clone() throws CloneNotSupportedException {
AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
result.keySet = null;
result.values = null;
return result;
}
/**
*
*/
private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
/**
* 说明:SimpleEntry和SimpleImmutableEntry是明显不相关的类,即使他们有共享相同的代码。
*/
/**
* 一个entry包含一个key和一个value.value可以通过setValue方法改变。
* 这个类促进构建自定义map的实现。例如,通过Map.entrySet().toArray方法来返回一个SimpleEntry数组是很方便的。
*/
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;
/**
* 创建一个entry代表一个指定的key和value的映射关系
*/
public SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
}
/**
* 创建一个entry表示了指定的相同的entry映射关系
*/
public SimpleEntry(Entry<? extends K, ? extends V> entry) {
this.key = entry.getKey();
this.value = entry.getValue();
}
/**
* 返回与此entry对应的key
*/
public K getKey() {
return key;
}
/**
* 返回与此entry对应的value
*/
public V getValue() {
return value;
}
/**
* 用指定的value代替entry中的value
*/
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
/**
* 比较指定的对象和entry.
* 同Map描述
*/
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());
}
/**
* 同map中的描述
*/
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
public String toString() {
return key + "=" + value;
}
}
/**
* 一个entry保持了不变的key和value。这个类不支持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;
/**
* 生成一个entry代表一个指定key和value的映射关系。
*/
public SimpleImmutableEntry(K key, V value) {
this.key = key;
this.value = value;
}
/**
* 根据指定的entry生成一个entry
*/
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) {
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;
}
}
}
--完--