Java容器解析系列(10) Map AbstractMap 详解
前面介绍了List
和Queue
相关源码,这篇开始,我们先来学习一种java
集合中的除Collection
外的另一个分支------Map
,这一分支的类图结构如下:
这里为什么不先介绍Set相关:因为很多Set实现类是通过对应的Map来实现,使用Map中key不能重复的特性,往Set中add元素的本质就是Map的put(),这里先介绍Map,后续介绍Set的时候再做具体介绍
首先,我们来看Map
接口:
/**
Map将key映射到value(存储键值对);
一个map不能存在重复的key;
一个key最多可以映射到1个value;
这个接口用来替换Dictionary抽象类;
* @since 1.2
*/
public interface Map<K,V> {
// Query Operations
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
// 按照指定键获得相对应的值;
// 如果不能存在指定键值对则返回null;
V get(Object key);
// Modification Operations
// 可选操作;添加指定键值对
V put(K key, V value);
// 可选操作;
// 移除指定键值对;
// 返回移除前key对应的value;
V remove(Object key);
// Bulk Operations
void putAll(Map<? extends K, ? extends V> m);
void clear();
// Views
// 返回Map中所有key的视图
Set<K> keySet();
// 返回Map中所有value的视图
Collection<V> values();
// 返回Map中所有的Entry的视图,也即key-value的视图
Set<Map.Entry<K, V>> entrySet();
// 一个Entry就是一个键值对;
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
}
// Comparison and hashing
boolean equals(Object o);
int hashCode();
}
和所有集合接口一样,Map接口主要是定义键值对相关的增删改查的操作,考虑到实现不可修改的Map的实现,其中增加(其实也包括修改)和删除都是可选操作.
Map接口中必须实现的方法主要是围绕着查找遍历Map:
Map中提供了3种遍历方式:
- 使用
keySet()
获取所有key的集合,然后用集合里面的可以获取所有value; - 使用
values()
获取所有value的集合; - 使用
entrySet()
获取所有key-value的集合;
其使用代码案例如下:
Set set = map.keySet();
for (Object key : set) {
System.out.println(map.get(key));
}
Collection values = map.values();
Iterator iterator = values.iterator();
while (iterator.hasNext()){
System.out.println("value " + iterator.next());
}
Set entrySet = map.entrySet();
for (Object o : entrySet) {
Map.Entry entry = (Map.Entry) o;
System.out.println(entry); //key=value
System.out.println(entry.getKey() + " / " + entry.getValue());
}
和之前介绍的集合类一样,Map
相关也提供了一个AbstractMap
抽象类,提供Map的骨架实现,其所有功能都是通过entrySet()
来实现,下面是其源代码:
为了简略篇幅,这里只列出部分具代表性的方法源码,具体可以参考
jdk
源码
/**
* 提供Map接口的骨架实现;
* 如果要实现一个不可修改的map,只需要继承该类,并实现entrySet方法,其返回的Set应不可修改;
* @since 1.2
*/
public abstract class AbstractMap<K, V> implements Map<K, V> {
protected AbstractMap() {}
// Query Operations
public int size() {
return entrySet().size();
}
public boolean isEmpty() {
return size() == 0;
}
public boolean containsValue(Object value) {
// ...
}
public boolean containsKey(Object key) {
// ...
}
// 通过entrySet()来实现,其实所有的方法都是通过entrySet()来实现
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;
}
// Modification Operations
// 默认不允许添加键值对
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
// 通过entrySet()实现,如果entrySet()不支持移除,其remove()会抛出UnsupportedOperationException
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();
}
// Views
transient volatile Set<K> keySet = null;
transient volatile Collection<V> values = null;
public Set<K> keySet() {
// ...
}
public Collection<V> values() {
// ...
}
// entrySet()仍然为抽象方法,待子类实现
public abstract Set<Entry<K, V>> entrySet();
// Comparison and hashing
public boolean equals(Object o) {
// ...
}
public int hashCode() {
// ...
}
public String toString() {
// ...
}
protected Object clone() throws CloneNotSupportedException {
// ...
}
private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
除了上面的之外,在jdk
1.6之后,AbstractMap
还提供了SimpleEntry
和SimpleImmutableEntry
两个静态内部类,其均实现了Map.Entry
接口,两者的唯一区别为SimpleImmutableEntry
不支持修改key
对应的value
,其setValue()
如下:
public V setValue(V value) {
throw new UnsupportedOperationException();
}
SimpleEntry
的源代码如下,没有什么需要特别讲解的:
/**
* @since 1.6
*/
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;
}
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;
}
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;
}
}
Java容器解析系列(10) Map AbstractMap 详解的更多相关文章
- Java容器解析系列(5) AbstractSequentialList LinkedList 详解
AbstractSequentialList为顺序访问的list提供了一个骨架实现,使实现顺序访问的list变得简单; 我们来看源码: /** AbstractSequentialList 继承自 A ...
- Java容器解析系列(0) 开篇
最近刚好学习完成数据结构与算法相关内容: Data-Structures-and-Algorithm-Analysis 想结合Java中的容器类加深一下理解,因为之前对Java的容器类理解不是很深刻, ...
- Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解
Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解 一.Jquery遍历筛选数组 1.jquery grep()筛选遍历数组 $().ready( function(){ v ...
- Java容器解析系列(11) HashMap 详解
本篇我们来介绍一个最常用的Map结构--HashMap 关于HashMap,关于其基本原理,网上对其进行讲解的博客非常多,且很多都写的比较好,所以.... 这里直接贴上地址: 关于hash算法: Ha ...
- Java 容器源码分析之集合类详解
集合类说明及区别 Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └W ...
- Java容器解析系列(13) WeakHashMap详解
关于WeakHashMap其实没有太多可说的,其与HashMap大致相同,区别就在于: 对每个key的引用方式为弱引用; 关于java4种引用方式,参考java Reference 网上很多说 弱引用 ...
- Java容器解析系列(14) IdentityHashMap详解
IdentityHashMap,使用什么的跟HashMap相同,主要不同点在于: 数据结构:使用一个数组table来存储 key:value,table[2k] 为key, table[2k + 1] ...
- Java容器解析系列(7) ArrayDeque 详解
ArrayDeque,从名字上就可以看出来,其是通过数组实现的双端队列,我们先来看其源码: /** 有自动扩容机制; 不是线程安全的; 不允许添加null; 作为栈使用时比java.util.Stac ...
- Java容器解析系列(9) PrioriyQueue详解
PriorityQueue:优先级队列; 在介绍该类之前,我们需要先了解一种数据结构--堆,在有些书上也直接称之为优先队列: 堆(Heap)是是具有下列性质的完全二叉树:每个结点的值都 >= 其 ...
随机推荐
- curl 向远程服务器传输file文件
public function upload(){ //获取上传文件信息,文件名称以自己实际上传文件名称为准 $fileinfo = $_FILE['filename']; //请求参数,依据商户自己 ...
- (转)通过maven,给没有pom文件的jar包生成pom文件,maven项目引入本地jar包
文章完全转载自 : https://blog.csdn.net/qq_31289187/article/details/81117478 问题一: 经常遇到公司私服或者中央仓库没有的jar包,然后通过 ...
- 第一次java程序设计作业
通过JAVA语言的学习,使我对计算机语言有了更加深入的认识和理解.知道了许多JAVA语言与其他语言的区别和特性,及其在我们生活中所发挥的重要作用.最后用一句话表明在学习JAVA语言过程中的感受,那就是 ...
- nameode启动过程
namenode在内存和磁盘中都保存了fsimage和edits文件 内存中保证hdfs文件系统的访问效率,磁盘中保证hdfs文件系统的安全性 namenode的文件组成: fsimage文件:保存文 ...
- POJ-3450 Corporate Identity (KMP+后缀数组)
Description Beside other services, ACM helps companies to clearly state their “corporate identity”, ...
- MySQL常用语法命令及函数
#创建数据库# create database 数据库名; #查看数据库# show databases; #选择数据库# use 数据库名; #删除数据库# drop database 数据库名; ...
- JAVA写接口傻瓜(%)教程(五)
今天主要说一下在URL 中使用?传值的问题.在显式的使用get方法获取特点数据时,一般会通过?传递参数值,sevlert根据参数在数据库中对应的查找内容.所以,SQL语句需要拼接,要加上后面的参数.参 ...
- git操作大全
分支克隆 1. git clone [git路径] #克隆仓库代码 2. git clone [Git路径] -b [分支name] #克隆仓库下某分支代码 查看分支 1.git branch #查看 ...
- div凹角实现
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 【还是回来了】博客搬家--https://cangbean.github.io
还是弄了个自己的地址:https://cangbean.github.io 想记录下,防止万一以后迁移不好弄 想练习markdown写作 折腾而已 以后不再博客园记录东西了,但是还是会回来看看的