Java容器分析--Map

转载 2006年06月02日 10:55:00

原文作者:Flyingis

原文地址:http://www.blogjava.net/flyingis/archive/2005/12/27/25534.html

标准的Java类库中包含了几种类型的Map,它们都拥有同样的基本接口Map,但是行为特性各不相同,主要表现在效率、键值对的保存、元素呈现次序、对象的保存周期和判定键是否等价的策略等方面。

1.Map的功能方法
Map(interface): 维护labelvalue的关联性,使得可以通过label查找value
HashMap: Map基于散列表的实现,取代了Hashtable。插入和查询label/value的开销是固定的,并且可以通过构造器设置容量和负载因子,以调整容器的性能。
LinkedHashMap: HashMap的基础上做了一些改进,在迭代遍历它时,取得label/value的顺序是其插入的次序,或者是最近最少使用(LRU)的次序,速度上比HashMap要慢一点,但在迭代访问时速度会更快,主要原因是它使用了链表维护内部次序。
TreeMap: 查看labellabel/value时,元素会被排序,其次序由ComparableComparator决定,因此查询所得到的结果是经过排序的。另外,它是唯一带有subMap()方法的Map具体类,即返回一个子树。它也是SortedMap接口的唯一实现,subMap()方法也是从该接口继承的。
WeakHashMap: Weak Key映射,允许释放映射所指向的对象。当映射之外没有引用指向某个label时,此label可以被垃圾收集器回收。
IdentityHashMap: 使用==代替equals()label进行比较的散列映射。
2.hashCode()
         当使用标准库中的类Integer作为HashMaplabel时,程序能够正常运行,但是使用自己创建的类作为HashMaplabel时,通常犯一个错误。
         HashMap中通过label查找value时,实际上是计算label对象地址的散列码来确定value的。一般情况下,我们是使用基类Object的方法hashCode()来生成散列码,它默认是使用对象的地址来计算的,因此由第一个对象new Apple(5)和第二个对象new Apple(5)生成的散列码是不同的,不能完成正确的查找。通常,我们可以编写自己的hashCode()方法来覆盖基类的原始方法,但与此同时,我们必须同时实现equals()方法来判断当前的label是否与表中存在的label相同。正确的equals()方法满足五个条件:
(1)     自反性。对于任意的xx.equals(x)一定返回true
(2)     对称性。对于任意的xy,如果y.equals(x)返回true,则x.equals(y)也返回true
(3)     传递性。对于任意的xyz,如果有x.equals(y)返回truey.equals(z)返回true,则x.equals(z)一定返回true
(4)     一致性。对于任意的xy,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false
(5)     对任何不是nullxx.equals(null)一定返回false
equals()比较的是对象的地址,如果要使用自己的类作为HashMaplabel,必须同时重载hashCode()equals()方法。
使用散列的目的:想要使用一个对象来查找另一个对象。使用TreeSetTreeMap也能实现此目的。另外,还可以自己实现一个Map,此时,必须提供Map.entrySet()方法来生成Map.Entry对象的Set
使用散列的价值:速度,散列使得查询可以快速进行。散列将label保存载数组中方便快速查询,因为存储一组元素最快的数据结构是数组,用它来表示label的信息(后面有信息的描述),而不是label本身。通过label对象计算得到一个数字,作为数组的下标,这个数字就是散列码(即前面所述的信息)。该散列码具体是通过定义在基类Object中,可能由程序员自定义的类覆盖的hashCode()方法,即散列函数生成。为了解决数组容量带来的限制,可以使不同的label生成相同的下标,保存在一个链表list中,每一个链表就是数组的一个元素。查询label时就可以通过对list中的信息进行查找,当散列函数比较好,数组的每个位置中的list长度较短,则可以快速查找到数组元素list中的某个位置,提高了整体速度。
散列表中的slot通常称为bucket,为了使散列分步均匀,bucket的值一般取质数。但事实证明,质数实际上并不是散列bucket的理想容量,近来Java散列实现都使用2的幂,具体如何验证以后再续。
3.HashMap的性能因子
容量(capacity): 散列表中bucket的数量。
初始化容量(initial capacity): 创建散列表时bucket的数量。可以在构造方法中指定HashMapHashSet的初始化容量。
尺寸(size): 散列表中记录的数量。(数组的元素个数,非list中元素总和)
负载因子(load factor): 尺寸/容量。负载因子为0,表示空的散列表,0.5表示半满的散列表。轻负载的散列表具有冲突少,适宜插入与查询的特点,但是使用迭代器遍历会比较慢。较高的负载会减少所需空间大小。当负载达到指定值时,容器会自动成倍地增加容量,并将原有的对象重新分配,存入新的bucket中,这个过程称为“重散列”。
4.重写hashCode()的关键
(1)     对同一个对象调用hashCode()都应该生成同样的值。
(2)     hashCode()方法不要依赖于对象中易变的数据,当数据发生变化时,hashCode()就会生成一个不同的散列码,即产生了一个不同的label
(3)     hashCode()不应依赖于具有唯一性的对象信息,例如对象地址。
(4)     散列码应该更关心速度,而不是唯一性,因为散列码不必是唯一的。
(5)     好的hashCode()应该产生分步均匀的散列码。在Effective Java(Addison-Wesley 2001)中,Joshua BlochhashCode()给出了设计指导,可以参考。

编写正确高效的hashCode()equals()可以参考ApacheJakarta Commons项目中的工具。

Java Map容器小示例

Map容器:键值对(Key-Value);关联数组。 Map里面的key和value都可以是任意的对象,比如Integer,或者一个很复杂的类对象。 Java里面的Map都封装得比较好了,所以使用...
  • Lv_Victor
  • Lv_Victor
  • 2016年08月09日 23:28
  • 545

Java容器分析--Map

Java容器分析--Map     作者:Flyingis 标准的Java类库中包含了几种类型的Map,它们都拥有同样的基本接口Map,但是行为特性各不相同,主要表现在效率、键值对的保存、...
  • wumengchao
  • wumengchao
  • 2014年03月20日 15:48
  • 199

Java容器分析--Map

标准的Java类库中包含了几种类型的Map,它们都拥有同样的基本接口Map,但是行为特性各不相同,主要表现在效率、键值对的保存、元素呈现次序、对象的保存周期和判定键是否等价的策略等方面。 1.Map...
  • selaginella
  • selaginella
  • 2014年10月22日 10:10
  • 484

map容器的详细用法

map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候...
  • kavu1
  • kavu1
  • 2016年10月06日 17:28
  • 1262

C++ map容器 学习笔记

map映照容器的元素数据是一个由键值和一个映照数据组成的,键值与映照数据之间具有一一映照的关系。 map映照容器的数据结构也是采用红黑树来实现的,插入元素的键值不允许重复,比较函数只对元素的键值进行...
  • u012823258
  • u012823258
  • 2014年02月24日 22:11
  • 1321

C++关联容器 map用法

原创作品 转载请注明出处 http://blog.csdn.net/always2015/article/details/44980187关联容器关联容器和顺序容器有着根本的不同:关联容器中...
  • Always2015
  • Always2015
  • 2015年04月10日 15:21
  • 1359

map容器的一些方法说明

#include #include #include #include using namespace std; int _tmain(int argc, _TCHAR* argv[]) {...
  • diaolingle
  • diaolingle
  • 2016年05月12日 23:38
  • 1145

Map容器的使用

最全的c++map的用法 此文是复制来的0.0 1. map最基本的构造函数; mapmapstring; mapmapint; mapmapstring; mapmapchar; mapmapc...
  • baidu_23955875
  • baidu_23955875
  • 2015年06月09日 12:51
  • 960

java基础-数据容器之Map-HashMap

数据容器     在程序代码中,用来暂时存储数据的“盒子”(容器),用于后续的逻辑处理。 为什么需要map? map是数据容器中的一种数据结构,首先它是用来存储数据的;其次,与其它数据容器不同,它...
  • yangspgao
  • yangspgao
  • 2017年12月22日 08:45
  • 47

C++ STL 中 map 容器的说明和使用技巧

Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!    1、map简介 map是一类关联...
  • u014552726
  • u014552726
  • 2014年07月22日 10:04
  • 8516
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java容器分析--Map
举报原因:
原因补充:

(最多只允许输入30个字)