Abstract 内容很简单,但是中间还是有一些细节需要注意
学习了 Map 接口源码后,开始下一步 AbstractMap
首先我们先回顾一下Map 的族谱
1、Map 族谱
从图谱中可以明显的看出 AbstractMap 扮演了一个很重要的角色。
下面我们来看看 AbsctractMap 中到底有哪些东西吧
2、接口定义
// 包:java.util
package java.util;
import java.util.Map.Entry;
public abstract class AbstractMap<K,V> implements Map<K,V> {}
3、属性字段
在 AbstractMap 类中,一共只有两个字段 keySet 、values
transient Set<K> keySet;
transient Collection<V> values;
按照基本知识,这两个字段是不可被序列化的
不可序列化:被 static 修饰、被 transient 修饰的字段
4、内部类
开始之前我们还是简单回顾一下 Entry<K,V>
方法 | 类型 | 说明 |
---|---|---|
K getKey() | abstract | 获得键 |
V getValue() | abstract | 获得值 |
V setValue(V value) | abstract | 设置值 |
boolean equals(Object o) | abstract | 判断与另一个对象是否相等 |
int hashCode() | abstract | 获取 Hash 值 |
<K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() | static | 根据键比较大小,要求键的类型继承 Comparable |
<K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() | static | 根据值比较大小,要求值的类型继承 Comparable |
<K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) | static | 自定义比较器,根据键比较大小 |
<K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) | static | 自定义比较器,根据值比较大小 |
4.1 SimpleEntry
这一个类是继承了 Map 中的 内部接口 Entry<K,V>
而这里的 SimpleEntry<K,V> 不仅继承了 Map.Entry<K,V> ,还继承了 序列化的接口
4.1.1 构造方法
方法 | 说明 |
---|---|
SimpleEntry(K key, V value) | 通过键值对初始化对象 |
SimpleEntry(Entry<? extends K, ? extends V> entry) | 通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化 |
4.1.2 普通方法
方法 | 说明 |
---|---|
K getKey() | 获取键 |
V getValue() | 获取值 |
V setValue(V value) | 设置新的值,并且返回旧值 |
boolean equals(Object o) | 如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同 |
int hashCode() | 计算该对象的 hash 值 |
String toString() | 将该对象转化为字符串 |
源码
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;
}
/** 通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化 */
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;
}
/** 如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同 */
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());
}
/** 计算该对象的 hash 值 */
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
/** 将对象转换为字符串,为方便输出 */
public String toString() {
return key + "=" + value;
}
}
4.2 SimpleImmutableEntry
4.2.1 接口定义
同 SimpleEntry 一样,都继承了 Map.Entry<K,V> 和 序列化接口
public static class SimpleImmutableEntry<K,V>
implements Entry<K,V>, java.io.Serializable{}
4.2.2 构造方法
方法 | 说明 |
---|---|
SimpleImmutableEntry(K key, V value) | 通过键值对初始化对象 |
SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) | 通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化 |
4.2.3 普通方法
方法 | 说明 |
---|---|
K getKey() | 获取键 |
V getValue() | 获取值 |
V setValue(V value) | 这里并不能使用这个方法,调用这个方法将会直接抛出错误 |
boolean equals(Object o) | 如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同 |
int hashCode() | 计算该对象的 hash 值 |
String toString() | 将该对象转化为字符串 |
源码
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;
}
/** 通过继承了Map.Entry<K,V> 的类来初始化,获取其中的 K,V 进行初始化 */
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();
}
/** 如果对象是 Map.Entry<K,V> 的实现类,分别比较两个类的键、值是否相同 */
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());
}
/** 计算该对象的 hash 值 */
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
/** 将该对象转化为字符串,多用于打印对象 */
public String toString() {
return key + "=" + value;
}
}
4.3 思考
Question:可以看到SimpleEntry 和 SimpleImmutableEntry 几乎是 95%相似的,为什么要写这么写?
1、从方法区别上来看, SimpleEntry 是可变值,SimpleImmutableEntry 是值不可变的,也就是 SimpleEntry 的值可变
2、从内部字段来看,SimpleEntry 只有键不可变, SimpleImmutableEntry 键值都不可变
// SimpleEntry private K key; private final V value; // SimpleImmutableEntry private final K key; private final V value; /** 错误; final Integer a = 1; a = 2; */
5、静态方法-eq
方法 | 说明 |
---|---|
eq(Object o1, Object o2) | 如果两个对象都不为空,判断两个兑对象是否相等 |
/** 如果两个对象都不为空,判断两个兑对象是否相等 */
private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
6、抽象方法-entrySet
entrySet 一般用于迭代的,将其中的数据取出
方法 | 说明 |
---|---|
Set<Entry<K,V>> entrySet() | 将 Map 中的每一对键值对,存入Set中,常用于遍历 |
public abstract Set<Entry<K,V>> entrySet();
7、普通方法
7.1 添加键值对
方法 | 说明 |
---|---|
V put(K key, V value) | 直接抛出异常,不可通过此方法新增键值对 |
void putAll(Map<? extends K, ? extends V> m) | 将传入 Map 集合中的所有键值对添加到该 Map |
7.1.1 put(K key, V value)
/** 直接抛出异常,不可通过此方法新增键值对 */
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
7.1.2 putAll(Map<? extends K, ? extends V> m)
/** 将传入 Map 集合中的所有键值对添加到该 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());
}
7.2 获取数据
说明 | 方法 |
---|---|
V get(Object key) | 通过键获取值 |
/** 通过键获取值 */
public V get(Object key) {
// 将键值对存储到 Set 中,将其迭代
Iterator<Entry<K,V>> i = entrySet().iterator();
// 寻找键为null的值
if (key == null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey() == null)
return e.getValue();
}
} else { //寻找 键不为 null 的的值
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return e.getValue();
}
}
return null;
}
7.3 移除元素
方法 | 说明 |
---|---|
V remove(Object key) | 根据键值移除键值对,并且返回键对应的值 |
void clear() | 清除 Map 中的所有的键值对 |
7.3.1 remove(Object key)
/** 根据键值移除键值对,并且返回键对应的值 */
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;
}
7.3.2 clear()
/** 清除 Map 中的所有的键值对 */
public void clear() {
entrySet().clear();
}
7.4 对 Map 操作
方法 | 说明 |
---|---|
int size() | 获取 Map 中键值对的数量 |
Object clone() | 将 Map 克隆,并将其中的 keySet 和 记录所有值得 values 集合清空 |
boolean isEmpty() | 判断 Map 里面有没有东西 |
7.4.1 size()
/** 获取 Map 中键值对的数量 */
public int size() {
return entrySet().size();
}
7.4.2 clone()
/** 将 Map 克隆,并将其中的 keySet 和 记录所有值得 values 集合清空 */
protected Object clone() throws CloneNotSupportedException {
AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
result.keySet = null;
result.values = null;
return result;
}
7.4.3 sEmpty()
/** 判断 Map 里面有没有东西 */
public boolean isEmpty() {
return size() == 0;
}
7.5 为迭代而生 ★
这两个方法的具体实现是典型的
抽象方法中 entrySet 同样也是,只不过这里没有实现
说明 | 方法 |
---|---|
Set<K> keySet() | keySet() 方法是将 Map 中所有的键存储到一个 Set 集合中 |
Collection<V> values() | 将 Map 中的内容存储到 Collection 集合 中,进行返回 |
7.5.1 keySet
使用场景:遍历的时候,通过遍历Set 取出其中的 Key ,再通过 key 获取 Value
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;
}
7.5.2 values
/** 将 Map 中的内容存储到 Collection 中,进行返回 */
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;
}
7.6 查询 Map 是否有对应的 Key/Value
方法 | 说明 |
---|---|
boolean containsKey(Object key) | 判断 Map 中是否有该键 |
boolean containsValue(Object value) | 判断 Map 中是否有该值 |
7.6.1 containsKey(Object key)
/** 判断 Map 中是否有该键 */
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;
}
7.6.2 containsValue(Object value)
/** 判断 Map 中是否有该值 */
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;
}