容器--Map和AbstractMap
一、前言
前面我们介绍了Collection接口的定义及一系列实现,并重点介绍了List体系下的一些实现,对于Collection来说,其实还有Set系列同样很重要,但由于Set是依赖于Map实现的,所以我们在这里先介绍Map.
Collection的特点是存储一类元素的集合,而Map则描述了一组映射关系的集合,即我们常说的key-value结构。这类容器的特点是容器中的每一项都是一个键值对,键的值不能重复,但允许有null键和null值的存在,一个键只能对应一个值,但多个不同的键可以对应于同一个值。
由于键值的惟一性,所以其key集合就天然是一个Set, 因此,JDK的set实现也正是基于这样的思想,使用了Map中的key集合来实现。
二、主要方法
虽然存储的元素不一样,但同为集合,Map和Collection之间还是有很多功能相似甚至是相同的功能,下面一个表格进行对比如下:
| 方法描述 | Map方法名 | Collection方法名 |
| 容器中元素个数 | size() | size() |
| 判断容器是否为空 | isEmpty() | isEmpty() |
| 添加元素 | put(K key, V value) | add(E e) |
| 批量添加元素 |
putAll(Map<K, V> map) |
addAll(Collection<E> collection) |
| 删除元素 | remove(Object key) |
remove(Object obj) removeAll(Collection<E> collection) retainAll(Collection<E> collection) |
| 清空列表 | clear() | clear() |
| 判断元素是否存在 |
containsKey(Object key) containsValue(Object value) |
contains(Object e) containsAll(Collection<E> e) |
| 遍历 |
keySet() entrySet() values() |
iterator() |
| 比较 | equals(Object obj) | equals(Object o) |
| 求hash | hashCode() | hashCode() |
| 根据key查找value | V get(Object key) | 无对应方法 |
| 转化为数组 | 无对应方法 |
toArray() toArray(T[] t) |
从上表我们可以看到,这两个容器都提供了对容器的增加,修改,删除及遍历的功能,对于Map来说,由于其特有的映射结构提供了根据key查找value的功能,而Collection由于是一组类型相同的元素,所以提供了转化为toArray的方法。
三、AbstractMap的实现原理
AbstractMap作为Map的抽象实现类,提供了绝大多数方法的实现。其中的惟一个未实现的方法是entrySet()方法,返回一个元素类型为Map.Entry的Set.
1)由于Set属于Collection,通过上表的比较我们可以知道Collection和Map的绝大部分功能是相似的,所以对于这些功能的实现就可以根据entrySet的相应方法来实现。比如对于删除方法,JDK是这样实现的:
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;
}
2)不支持put方法的实现,相应的,putAll方法由于调用了put,所以这个方法也不支持。
3)根据定义,map中的key和value都有可能为null,所以判断一个map中是否包含某个key,不应该根据get(key) == null来判断 ,而应该调用containsKey(key)来判断。
4)keySet()和values()使用了匿名内部类的方式来实现,主要的实现逻辑是重写了抽象容器类的iterator方法,将其遍历转化为对于key和值的遍历。
三、总结
AbstractMap通过将entrySet定义为抽象方法的方式,巧妙的将具体的实现和存储逻辑交给子类实现,这样实现者可以专注于元素的存储,另外,通过学习AbstractMap中的方法实现,我们可以借鉴其map的遍历方式,正确的应该是先找到entrySet,就像下面这样:
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;
}
在遍历时,我们使用iterator(), 而不是使用for(String key : map.keySet())的方式。因为这种方式的问题在于,如果按抽象类的实现方式,map.keySet()相当于是需要对整个map进行遍历,而在for循环中, 对于map.get(key)来说,实际上又需要遍历整个map,循环多少次,就遍历多少次,这确实是非常低效率的。
当然,也许HashMap并不会在get(key)时遍历整个map,但这并不能保证其它的实现不是这样,所以,iterator才是正理。
明天会继续学习HashMap.
容器--Map和AbstractMap的更多相关文章
- C++关联容器<map>简单总结
C++关联容器<map>简单总结 map提供大小可变的关联容器,基于关联键值高效检索元素值.当你处理键值对的数据是,都可以考虑使用map关联容器. 特点: 大小可变的关联容器,基于关联键值 ...
- 关联容器——map、set
map类型通常被称为关联数组,与正常数组类似,不同之处在于其下标不必是整数.我们通过一个关键字而不是位置来查找值(键值对). 与之相对,set就是关键字的简单集合.当只是想知道一个值是否存在时,set ...
- c++中关联容器map的使用
C++关联容器<map>简单总结(转) 补充: 使用count,返回的是被查找元素的个数.如果有,返回1:否则,返回0.注意,map中不存在相同元素,所以返回值只能是1或0. 使用find ...
- Java容器Map接口
Map接口容器存放的是key-value对,由于Map是按key索引的,因此 key 是不可重复的,但 value 允许重复. 下面简单介绍一下Map接口的实现,包括HashMap,LinkedHas ...
- spring 中容器 map、set、list、property 的 bean 实例化
参考:http://www.kaifajie.cn/spring/9966.html <bean id="fieldMap" class="org.springfr ...
- C++ 之关联容器 map
标准库定义了四种关联容器:map是其中之一(另外还有set.multimap.multiset).map的元素以键-值(key-value),在学了顺序容器之后,再学习关联容器,就比较比较好理解了. ...
- 关联容器(map):支持高效查找的容器,一种键值对的集合。
#include <iostream> #include <string> #include <map> #include <vector> using ...
- Java容器---Map基础
1.Map API (1)Map 集合类用于存储元素对(称作"键"和"值"),其中每个键映射到一个值. java.util Interface Map<K ...
- java并发容器(Map、List、BlockingQueue)
转发: 大海巨浪 Java库本身就有多种线程安全的容器和同步工具,其中同步容器包括两部分:一个是Vector和Hashtable.另外还有JDK1.2中加入的同步包装类,这些类都是由Collectio ...
随机推荐
- 深度解析SDN——利益、战略、技术、实践(实战派专家力作,业内众多专家推荐)
深度解析SDN——利益.战略.技术.实践(实战派专家力作,业内众多专家推荐) 张卫峰 编 ISBN 978-7-121-21821-7 2013年11月出版 定价:59.00元 232页 16开 ...
- iOS开发——网络使用技术OC篇&网络爬虫-使用正则表达式抓取网络数据
网络爬虫-使用正则表达式抓取网络数据 关于网络数据抓取不仅仅在iOS开发中有,其他开发中也有,也叫网络爬虫,大致分为两种方式实现 1:正则表达 2:利用其他语言的工具包:java/Python 先来看 ...
- jQuery_01之选择器
1.jQuery对象获取:①先获得DOM对象,再用$函数封装到jQuery对象:var $jQuery=$(DOM对象):②直接使用$函数查找到的DOM对象,被自动封装到jQuery对象中:var $ ...
- javascript_core_05之正则表达式
1. 检索关键词: ①检索固定关键词的位置: var i=str.indexOf(“关键词”,fromi):在str中查找fromi位置后,下一个关键词的下标位置:省略fromi,从0开始: var ...
- 常用的java类型转json的转换类
公司不准引入json-lib-2.x.jar所以只好自己写了一个基本类型的object转json的类,然后支持8种基本类型和javabean,list,map,array,使用putJSON方法,ke ...
- dropzone的使用方法
http://www.renfei.org/blog/dropzone-js-introduction.html dropzone.js 是一个开源的 JavaScript 库,提供 AJAX 异步上 ...
- Geometry Curve of OpenCascade BRep
Geometry Curve of OpenCascade BRep eryar@163.com 摘要Abstract:几何曲线是参数表示的曲线 ,在边界表示中其数据存在于BRep_TEdge中,BR ...
- Android入门(十一)SQLite CURD
原文链接:http://www.orlion.ga/594/ 一.添加数据 SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法 ...
- 理解CSS中的数学表达式calc()
前面的话 数学表达式calc()是CSS中的函数,主要用于数学运算.使用calc()为页面元素布局提供了便利和新的思路.本文将介绍calc()的相关内容 定义 数学表达式calc()是calculat ...
- php操作mongodb中的ISODate格式日期
mongodb 中数据记录的日期格式为"dateCreated" : ISODate("2011-12-20T07:22:50.836Z")经过翻阅php官网中 ...