功能:该类提供了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 AbstractMap<K,V> implements Map<K,V> {}
框架图:
变量 包变量 01.key的集合keySet
补充:transient
—— 标识此变量不进行序列化的关键字,当使用Serializable
序列化时不会被序列化(静态变量除外),使用Exteranlizable
序列化时根据重写的方法决定时进行序列化
// key的集合,Set类型,不可重复
transient Set<K> keySet;
02.value的集合 values
// value的集合,Collection类型
transient Collection<V> values;
方法
构造器
// 唯一构造器
protected AbstractMap() {}
内部类
01.可变的键值对 SimpleEntry
注意:
1. 本方法存在于1.6
及以后版本
2. 提供给实现类使用,本类未使用此内部类
3. 本方法不提供修改key
值的方法
// 源码
public static class SimpleEntry<K,V> implements Entry<K,V>, 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;
}
}
02.不可变的键值对 SimpleImmutableEntry
注意:
1. 本方法存在于1.6
及以后版本
2. 提供给实现类使用,本类未使用此内部类
3. 本方法不提供修改key
值的方法
4. 与SimpleEntry
仅有setValue
方法不同,使用本内部类时若修改value
会抛出UnsupportedOperationException
异常
// 源码
public static class SimpleImmutableEntry<K,V> implements Entry<K,V>, 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;
}
}
抽象方法
01.获取键值对映射关系的Set
对象 entrySet()
注意:
1. Set
的元素是唯一的
2. 一般可以使用此方法进行遍历,可以使用此方法将Map
转换为的Set
集合再使用迭代器循环
// 源码
public abstract Set<Entry<K,V>> entrySet();
// HashMap示例
@Test
void contextLoads() {
Map<String,Object> map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
// 此处直接返回的是一个Set,元素类型是Map.Entry<>
Set<Map.Entry<String, Object>> 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<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;
}
// 示例:使用HashMap实例
@Test
void contextLoads() {
Map<String,Object> 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<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;
}
// 示例:使用HashMap实例
@Test
void contextLoads() {
Map<String,Object> 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<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;
}
// 示例:使用HashMap实例
@Test
void contextLoads() {
Map<String,Object> 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<String,Object> 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<Entry<K,V>> i = entrySet().iterator();
Entry<K,V> correctEntry = null;
// 寻找指定key对应的键值对
if (key==null) {
// 找到指定key值并将键值对存入后退出循环
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;
}
}
// 此处若找到了键值对,则将值储存下来并通过迭代器移除(此处未进行next()移动游标就退出了循环)
V oldValue = null;
if (correctEntry !=null) {
oldValue = correctEntry.getValue();
i.remove();
}
return oldValue;
}
// 异常示例:生成迭代器后新增键值对
@Test
void contextLoads() {
Map<String,Object> map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
Set<Map.Entry<String, Object>> entries = map.entrySet();
Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
map.put("five",5);
while (iterator.hasNext()){
// java.util.ConcurrentModificationException
System.out.println(iterator.next());
}
}
// 示例:HashMap实例
@Test
void contextLoads() {
Map<String,Object> 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<String,Object> 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 Set<K> keySet() {
// 默认keySet未进行初始化为null,即ks为null
Set<K> ks = keySet;
if (ks == null) {
// 初始化,根据当前Map创建key的集合
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进行了赋值
keySet = ks;
}
return ks;
}
// 示例:HashMap实例
@Test
void contextLoads() {
Map<String,Object> 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 Collection<V> values() {
// 默认values未进行初始化为null,即vals为null
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;
}
// 示例:HashMap实例
@Test
void contextLoads() {
Map<String,Object> 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<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> 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<String,Object> 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<String,Object> 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<String,Object> map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
map.put("four",4);
map.put("zero",null);
Map<String,Object> 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<Entry<K,V>> i = entrySet().iterator();
// 哈希值依次递增上一个值的哈希值
while (i.hasNext())
h += i.next().hashCode();
return h;
}
14.输出为字符串 toString()
注意:输出格式 —— {key1=value1, key2=value2}
// 源码
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(' ');
}
}
// 示例:HashMap实例
@Test
void contextLoads() {
Map<String,Object> 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());
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)