JAVA中HashMap和HashTable 的理解

来源:互联网 发布:中国教育服务中心知乎 编辑:程序博客网 时间:2024/05/21 07:50
很早就觉得HashMap是很神奇的东西,有人曾经和我说如果不知道HashMap就不要去面试了,好像HashMap是JAVA语言世界里必备的元素一样。可能大家学JAVA之初时,都会觉得集合没什么用。等你真正开发软件工程去处理大量数据的时候会经常用到集合,而且学问非常深,非常讲究集合的效率、使用场景等,当然这里只说Map族的集合。它延伸开来是一个家族:HashSet / HashTable / TreeMap 等。说到底它就是一个仓库。就象米库,弹药库,成品库, 材料库, 只是管理的方式不同而已。Vector 和 LinkedList也是一种仓库,但他们到仓库找东西,总会很老实地一样一样翻过去,运气最差的情况,就是翻到最后一件物品才找到。而HashMap就聪明多了,先把仓库隔成几个区,然后你告诉他找什么,他会先计算你这个物品会放在第几区,直接到那里找就行了,比如弹药库,分成1区:枪区、2区:子弹区、3区、导弹区。如果要你找54式手枪的子弹,你直接去3区就行了,总不会总导弹区找子弹上膛。如果支持多个人进去找各自的物品,也就是线程不安全,但访问速度很快;每次限制一个人进去找,那么是线程安全,可是打仗的时候、明明你来拿子弹,它来拿导弹的,可还非得一个人在外边等,这多急。

        在数组(Vector和LinkedList)中,通过数组下标来对其内容索引;在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value。HashMap实现了接口Map,而接口Map接口 Map<K,V> 类型参数: K - 此映射所维护的键的类型;V - 映射值的类型。使用Map时指定K.V的具体类型就叫泛型编程。HashMap中插入和查询key/value的开销是一个固定常量。而数组的插入与查询可能与输入规模有关。HashMap不保证映射后的其内容的顺序在一定的时间内不会变化,也就是说,HashMap中元素的排列顺序是无序的,如果要用自己的类作为HashMap的key,必须同时覆盖hashCode和equals方法。说到这里有必要说下散列表和哈希函数。在数据结构中,有四种存储方式,分别是:顺序存储、链式存储、索引、散列。散列表也叫哈希表,需要存储的数据经过哈希函数的计算得到一个值,根据这个值存储到相应的位置。如:有若干个100以内的数,如果存放在5个盒子里,如果哈希函数 y = x % 5 ,这样得到的值就是key,再根据这个key值存储到编号为1,2,3,4,5的盒子里。这样就不可避免引出一个问题,如何最大程序地避免冲突。

         C++更多倾向于称这类仓库为集合,在JAVA的世界里,查阅了资料,更倾向叫“容器”,很多人知道C++,定义了一组集合称之为标准模板类库(STL),java中也定义了具有满足不同需要的各种类型的容器,List用于存储序列数据,Map用来存储对象之间的关联,Set每种对象类型只持有一个。很多局外人就十分纳闷为什么要搞那么多容器,如果单一类型的容器可以满足所有需要,那么就没有理由设计不同种类的容器了:第一、不同容器提供了不同类型的接口和外部行为。第二、不同的容器对于某些操作具有不同的效率。

       上边都依据HashMap来说明哈希家庭的独特性,在哈希家庭里还有Hashset和HashTable,这是重点展开对于HashMap与HashTable的不同点进行讨论,通俗的讲,hashtable 线程安全,但效率低,hashmap非线程安全,但效率高。它们的不同主要是历史原因。Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。

       1)当然最重要的不同是Hashtable的方法是同步的(线程安全),而HashMap的方法(非线程安全)不是。这就意味着,虽然你可以不用采取任何特殊的行为就可以在一个多线程的应用程序中用一个Hashtable,但你必须同样地为一个HashMap提供外同步。一个方便的方法就是利用Collections类的静态的synchronizedMap()方法,它创建一个线程安全的Map对象,并把它作为一个封装的对象来返回。这个对象的方法可以让你同步访问潜在的HashMap。这么做的结果就是当你不需要同步时,你不能切断Hashtable中的同步(比如在一个单线程的应用程序中),而且同步增加了很多处理费用。

       2)只有HashMap可以让你将空值作为一个表的条目的key或value。HashMap中只有一条记录可以是一个空的key,但任意数量的条目可以是空的value。这就是说,如果在表中没有发现搜索键,或者如果发现了搜索键,但它是一个空的值,那么get()将返回null。如果有必要,用containKey()方法来区别这两种情况。我的建议,当需要同步时,用Hashtable,反之用HashMap。但是,因为在需要时,HashMap可以被同步,HashMap的功能比Hashtable的功能更多,而且它不是基于一个陈旧的类的,所以有人认为,在各种情况下,HashMap都优先于Hashtable。

       3)HashTable使用Enumeration,HashMap使用Iterator。

       4)HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

原创粉丝点击