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数组与容器类分析资料--数组、List和Set、Map

Java数组与容器类分析资料--数组、List和Set、Map Java容器分析--数组     数组是Java语言内置的类型,除此之外,Java有多种保存对象引用的方式。Java类库...

Java数组与容器类分析资料–数组、List和Set、Map等

数组是Java语言内置的类型,除此之外,Java有多种保存对象引用的方式。Java类库提供了一套相当完整的容器类,使用这些类的方法可以保存和操纵对象。下面分别进行讨论,在研究Java容器类之前,先了解...

Java容器_Map_HashMap源码分析

Map是映射: (1)实现Map接口的类用于存储键(key)--值(Value)对; (2)Map接口的实现类有HashMap和TreeMap等; (3)Map类中存储的键值对通过键来标识,所以键值...

Java 编程思想(第4版)学习笔记(各种容器(集合框架)的比较 Collection Map ..第11章 练习4)

package Exer_11; import java.util.*; import static java.lang.System.out; /** * @author lzcysd *...

Java容器类List、ArrayList、Vector及map、HashTable、HashMap分别的区别

ArrayList和HashMap是异步的,Vector和HashTable是同步的,所以Vector和HashTable是线程安全的,而 ArrayList和HashMap并不是线程安全的。因为同步...

Java的容器 List、Set、Map的区别

在编程中,常常需要集中存放多个数据。从传统意义上讲,数组是我们的一个很好的选择,前提是我们事先已经明确知道我们将要保存的对象的数量。一旦在数组初始化时指定了这个数组长度,这个数组长度就是不可变的,如果...

Java 容器(四) Map

Java 容器(四) Map 1.Map的使用估计是最常见的了:  1)HashMap:存储的值可以重复,键不能;不能使用Comparator和Comparable接口排序;HashMap最多只允许一...

JAVA的容器---List Map Set

JAVA的容器---List Map SetJAVA的容器---List,Map,Set Collection├List│├LinkedList│├ArrayList│└Vector│└Stack└S...
  • cynhafa
  • cynhafa
  • 2011年05月26日 11:27
  • 362

Java内部的容器类之list set map的要点和不同点

Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └...

Java容器类Collection、List、ArrayList、Vector及map、HashTable、HashMap区别

Collection是List和Set两个接口的基接口  List在Collection之上增加了"有序"  Set在Collection之上增加了"唯一"  而ArrayList是实现Li...
  • amork
  • amork
  • 2012年02月14日 11:42
  • 1622
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java容器分析--Map
举报原因:
原因补充:

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