功能:该类提供了Map接口的基础框架
开始版本:JDK 1.2
注意:
1. 本类为抽象类
2. 使用key-value键值对储存,可以存在相同的value,不能存在相同的key,key和value均可为null
3. 数据结构:Map的数据结构种类较多,不同实现有不同的数据结构,大致包括顺序表、链表、树、散列表
备注:本类没有实现AbstractCollection,内部没有迭代器,因此Map不能直接使用迭代器循环
实现接口:java.util.Map
所在包:java.util
导入类:java.util.Map.Entry
类声明:
public abstract class AbstractMapimplements Map {}
框架图:
变量 包变量 01.key的集合 keySet补充:transient —— 标识此变量不进行序列化的关键字,当使用Serializable序列化时不会被序列化(静态变量除外),使用Exteranlizable序列化时根据重写的方法决定时进行序列化
// key的集合,Set类型,不可重复 transient Set02.value的集合 valueskeySet;
// value的集合,Collection类型 transient Collection方法 构造器values;
// 唯一构造器
protected AbstractMap() {}
内部类
01.可变的键值对 SimpleEntry注意:
1. 本方法存在于1.6及以后版本
2. 提供给实现类使用,本类未使用此内部类
3. 本方法不提供修改key值的方法
// 源码 public static class SimpleEntry02.不可变的键值对 SimpleImmutableEntryimplements Entry , java.io.Serializable { private static final long serialVersionUID = -8499721149061103585L; // key value 变量 private final K key; private V value; // 构造器,传key-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(); } // 获取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; } // 比较,调用eq方法进行key和value内容的比较 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()); } // 输出字符串,格式:key=value public String toString() { return key + "=" + value; } }
注意:
1. 本方法存在于1.6及以后版本
2. 提供给实现类使用,本类未使用此内部类
3. 本方法不提供修改key值的方法
4. 与SimpleEntry
// 源码 public static class SimpleImmutableEntry抽象方法 01.获取键值对映射关系的Set对象 entrySet()implements Entry , java.io.Serializable { private static final long serialVersionUID = 7138329143949025153L; // key value 变量 private final K key; private final V value; // 构造器,传key-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(); } // 获取key值 public K getKey() { return key; } // 获取value值 public V getValue() { return value; } // 设置value值,本内部类是不可变键值对,因此调用本方法会抛出异常 public V setValue(V value) { throw new UnsupportedOperationException(); } // 比较,调用eq方法进行key和value内容的比较 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()); } // 输出字符串,格式:key=value public String toString() { return key + "=" + value; } }
注意:
1. Set的元素是唯一的
2. 一般可以使用此方法进行遍历,可以使用此方法将Map转换为的Set集合再使用迭代器循环
// 源码 public abstract Set> entrySet();
// HashMap示例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
// 此处直接返回的是一个Set,元素类型是Map.Entry<>
Set> entries = map.entrySet();
// [one=1, two=2, three=3]
System.out.println(entries);
}
保护方法
01.克隆 clone()
注意:本方法需要重写,调用了Object的clone()
// 源码
protected Object clone() throws CloneNotSupportedException {
AbstractMap,?> result = (AbstractMap,?>)super.clone();
// 直接调用了Object的clone(),无实际实现,设置key集合和value集合为null
result.keySet = null;
result.values = null;
return result;
}
私有方法
01.比较两个对象是否一致 eq(Object o1, Object o2)
参数:
1. o1 —— 要比较的对象1
2. o2 —— 要比较的对象2
注意:此方法提供给内部类使用
// 源码
private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
公有方法
01.获取Map的元素个数 size()
注意:此处是将Map转换为Set后计算的个数
// 源码
public int size() {
return entrySet().size();
}
02.Map是否为空 isEmpty()
注意:此处是将Map转换为Set后计算的个数再进行判空的
// 源码
public boolean isEmpty() {
return size() == 0;
}
03.当前Map的value中是否包含某一元素 containsValue(Object value)
参数:value —— 要判断的value值
注意:
1. 指定元素为null需要单独比较,使用equals会出现空指针
2. 调用getValue()获取值
// 源码
public boolean containsValue(Object value) {
// 通过转换为的Set集合使用迭代器遍历
Iterator> i = entrySet().iterator();
if (value==null) {
while (i.hasNext()) {
Entry e = i.next();
if (e.getValue()==null)
return true;
}
} else {
while (i.hasNext()) {
Entry e = i.next();
if (value.equals(e.getValue()))
return true;
}
}
return false;
}
// 示例:使用HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
// true
System.out.println(map.containsValue(4));
}
04.当前Map的key中是否包含某一元素 containsKey(Object key)
参数:key —— 要判断的key值
注意:
1. 指定元素为null需要单独比较,使用equals会出现空指针
2. 调用getKey()获取Key
// 源码
public boolean containsKey(Object key) {
// 通过转换为的Set集合使用迭代器遍历
Iterator> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry e = i.next();
if (e.getKey()==null)
return true;
}
} else {
while (i.hasNext()) {
Entry e = i.next();
if (key.equals(e.getKey()))
return true;
}
}
return false;
}
// 示例:使用HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
// false
System.out.println(map.containsKey("six"));
}
05.根据key获取对应的value值 get(Object key)
参数:key —— 要获取的键值对的key
注意:
1. 指定元素为null需要单独比较,使用equals会出现空指针
2. 本方法实际是从头循环查找指定key的,根据实现类的底层数据结构不同时间复杂度等各不同
3. 需注意查找不到指定key返回的是null,查询指定key的值若为null,无法区别这两种情况,因此本方法不建议使用本方法判断Map中是否包含某个key,建议使用containsKey(Object key)
// 源码
public V get(Object key) {
// 通过转换为的Set集合使用迭代器遍历
Iterator> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry e = i.next();
if (e.getKey()==null)
return e.getValue();
}
} else {
while (i.hasNext()) {
Entry e = i.next();
if (key.equals(e.getKey()))
return e.getValue();
}
}
return null;
}
// 示例:使用HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
// null
System.out.println(map.get("six"));
// null
System.out.println(map.get("zero"));
}
06.存入Map键值对 put(K key,V value)
参数:
1. key —— 要存入的key值
2. value —— key对应的值
注意:
1. 此方法必须重写,否则会直接抛出UnsupportedOperationException异常
2. Map是否有序根据具体实现类的数据结构决定
// 源码
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
// 示例:HashMap实例
@Test
void contextLoads4() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("ooo",1.25);
map.put("four",4);
map.put("zero",null);
// HashMap无序:{zero=null, four=4, one=1, two=2, three=3}
System.out.println(map);
}
07.移除指定key值的键值对 remove(Object key)
参数:key —— 要移除的key值
注意:
1. 本方法使用了迭代器,生成的Set集合是动态的,会受Map集合影响,在生成迭代器后直接对Map进行操作仍会导致迭代器的ConcurrentModificationException异常
2. 指定元素为null需要单独比较,使用equals会出现空指针
3. 本方法返回的是移除的key对应的值,未找到元素则返回null,注意此处若移除的key的值为null也会返回null,无法根据返回值判断Map是否包含key
// 源码
public V remove(Object key) {
Iterator> i = entrySet().iterator();
Entry correctEntry = null;
// 寻找指定key对应的键值对
if (key==null) {
// 找到指定key值并将键值对存入后退出循环
while (correctEntry==null && i.hasNext()) {
Entry e = i.next();
if (e.getKey()==null)
correctEntry = e;
}
} else {
while (correctEntry==null && i.hasNext()) {
Entry e = i.next();
if (key.equals(e.getKey()))
correctEntry = e;
}
}
// 此处若找到了键值对,则将值储存下来并通过迭代器移除(此处未进行next()移动游标就退出了循环)
V oldValue = null;
if (correctEntry !=null) {
oldValue = correctEntry.getValue();
i.remove();
}
return oldValue;
}
// 异常示例:生成迭代器后新增键值对
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
Set> entries = map.entrySet();
Iterator> iterator = entries.iterator();
map.put("five",5);
while (iterator.hasNext()){
// java.util.ConcurrentModificationException
System.out.println(iterator.next());
}
}
// 示例:HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
// {zero=null, four=4, one=1, two=2, three=3}
System.out.println(map);
Object zero = map.remove("zero");
// null
System.out.println(zero);
Object six = map.remove("six");
// null
System.out.println(six);
Object two = map.remove("two");
// 2
System.out.println(two);
// {four=4, one=1, two=2, three=3}
System.out.println(map);
}
08.将指定Map内容存入指定对象 putAll(Map extends K, ? extends V> m)
参数:m —— 指定的储存键值对的对象
注意:
1. 当指定Map的key已存在于当前Map,覆盖之前key的值
2. 本方法实际是循环调用了put(K key, V value)方法,而put(K key, V value)方法需要重写
3. 本方法未使用迭代器循环,而是直接使用Set的增强for循环进行遍历的
// 源码
public void putAll(Map extends K, ? extends V> m) {
for (Map.Entry extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
09.清空全部键值对 clear()
注意:本方法调用的实际是Set的clear()方法
// 源码
public void clear() {
entrySet().clear();
}
// 示例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
// {zero=null, four=4, one=1, two=2, three=3}
System.out.println(map);
map.clear();
// {}
System.out.println(map);
}
10.获取key的集合 keySet()
注意:
1. 未调用过本方法,变量keySet为null,调用本方法时对keySet进行初始化并赋值
2. 本方法生成的集合仅有contains(Object k)方法和迭代器的next()方法实现不同,contains(Object k)方法调用的是containsKey(Object key)方法,next()方法调用的是getKey()
// 源码 public SetkeySet() { // 默认keySet未进行初始化为null,即ks为null Set ks = keySet; if (ks == null) { // 初始化,根据当前Map创建key的集合 ks = new AbstractSet () { public Iterator iterator() { // 创建一个普通的迭代器并初始化 return new Iterator () { private Iterator > 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进行了赋值 keySet = ks; } return ks; }
// 示例:HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
// [zero, four, one, two, three]
System.out.println(map.keySet());
}
11.获取value的集合 values()
注意:
1. 未调用过本方法,变量values为null,调用本方法时对values进行初始化并赋值
2. 本方法生成的集合仅有contains(Object k)方法和迭代器的next()方法实现不同,contains(Object k)方法调用的是containsValue(Object key)方法,next()方法调用的是getValue()
3. 本方法返回的是Collection集合,value可以重复
// 源码 public Collectionvalues() { // 默认values未进行初始化为null,即vals为null Collection vals = values; if (vals == null) { vals = new AbstractCollection () { public Iterator iterator() { return new Iterator () { private Iterator > 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; }
// 示例:HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
map.put("six",null);
// [null, null, 4, 1, 2, 3]
System.out.println(map.values());
}
12.比较 equals(Object o)
参数:o —— 比较的对象
// 源码
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> i = entrySet().iterator();
while (i.hasNext()) {
Entry e = i.next();
K key = e.getKey();
V value = e.getValue();
// 此处使用get()若不存在key也会返回null,因此需要多判断一个是否存在当前key值
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;
}
// 示例1:HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
map.put("six",null);
Map map2 = new HashMap<>();
map2.put("one",1);
map2.put("two",2);
map2.put("three",3);
map2.put("four",4);
map2.put("zero",null);
// false
System.out.println(map.equals(map2));
}
// 示例2:HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
Map map2 = new HashMap<>();
map2.put("one",1);
map2.put("two",2);
map2.put("three",3);
map2.put("four",4);
map2.put("zero",null);
// true
System.out.println(map.equals(map2));
}
13.哈希值 hashCode()
注意:计算方法 —— 依次递增上一个值的哈希值
// 源码
public int hashCode() {
int h = 0;
Iterator> i = entrySet().iterator();
// 哈希值依次递增上一个值的哈希值
while (i.hasNext())
h += i.next().hashCode();
return h;
}
14.输出为字符串 toString()
注意:输出格式 —— {key1=value1, key2=value2}
// 源码
public String toString() {
Iterator> i = entrySet().iterator();
if (! i.hasNext())
return "{}";
StringBuilder sb = new StringBuilder();
sb.append('{');
for (;;) {
Entry 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(' ');
}
}
// 示例:HashMap实例
@Test
void contextLoads() {
Map map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
map.put("six",null);
// {zero=null, six=null, four=4, one=1, two=2, three=3}
System.out.println(map.toString());
}



