容器--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 ...
随机推荐
- [javaweb]Java过滤器与包装设计模式的实用案例.
在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator(装饰器)模式对request.response对象进行包装,再把包装对象传给目 ...
- [JavaWeb]关于DBUtils中QueryRunner的一些解读.
前言:[本文属于原创分享文章, 转载请注明出处, 谢谢.]前面已经有文章说了DBUtils的一些特性, 这里再来详细说下QueryRunner的一些内部实现, 写的有错误的地方还恳请大家指出. Que ...
- Atitit.现在的常用gui技术与gui技术趋势评价总结
Atitit.现在的常用gui技术与gui技术趋势评价总结 1. Gui俩种分类: native 和 dsl 和 script1 2. 最好的跨平台gui技术h51 2.1. 几大技术体系(java ...
- KnockoutJS 3.X API 第二章 数据监控(1)视图模型与监控
数据监控 KO的三个内置核心功能: 监控(Observable)和依赖性跟踪(dependency tracking) 声明绑定(Declarative bindings) 模板(Templating ...
- KnockoutJS 3.X API 第四章 表单绑定(11) options绑定
目的 options绑定主要用于下拉列表中(即<select>元素)或多选列表(例如,<select size='6'>).此绑定不能与除<select>元素之外的 ...
- 新版本来袭:Apache Spark 1.5新特性介绍
年9月9日发布了1.5版本,该版本由230+开发人员和80+机构参与,修复了1400多个补丁,该版本可以通过 http://spark.apache.org/downloads.html进行下载.Sp ...
- 配置springmvc在其他类中(spring容器外)获取注入bean
学习https://github.com/thinkgem/jeesite 今天在写JedisUtils的时候要注入JedisPool,而这个属性被设置为static,@Resource和@Autow ...
- 这些HTML、CSS知识点,面试和平时开发都需要 No5-No7
系列知识点汇总 这些HTML.CSS知识点,面试和平时开发都需要 No1-No4(知识点:HTML.CSS.盒子模型.内容布局) 这些HTML.CSS知识点,面试和平时开发都需要 No5-No7(知识 ...
- C#控件及常用设计整
C#控件及常用设计整 1.窗体 1 2.Label 控件 3 3.TextBox 控件 4 4.RichTextBox控件 5 5.NumericUpDown 控件 7 ...
- [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析
[DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 场景模拟 假设由于漏存JD SKU对应的店铺信息.这时我们需要重新完全采集所有 ...