hashmap 的一些研究

来源:互联网 发布:大襟绸缎面花棉袄淘宝 编辑:程序博客网 时间:2024/05/01 12:27

今天面试被问到hashmap 的有关东西,结果这个很经典的结构我是了解它的原理,可是在语言中的具体实现原理还是不清楚的,仅仅是用过而已,所以回答的。。现在深入的整理一下:

在java 里面是有hashmap 的数据结构
在c++里面有map 的数据结构
介绍了java 中的hashmap 的原理
http://www.cnblogs.com/skywang12345/p/3310835.html
面试中关于java hashmap 的一点点深入  (好文!)
http://www.importnew.com/7099.html
c++ 中的hashmap (当在string 和char 作key值时候,是会出现问题的,得不到相应的value 值,但是有处理方法)
http://blog.csdn.net/srzhz/article/details/7881946  string 
http://www.cppblog.com/guojingjia2006/archive/2008/01/12/41037.aspx   char 
http://www.cnblogs.com/waytofall/archive/2012/06/04/2534386.html  <这篇文章讲得才是王道!>

两者比较:(这个写得很好,细节东西)
http://blog.csdn.net/mdj67887500/article/details/6907702


关键点:
java中的:
1、key 与 value 可null 无序的(linkmap 是有序的)
2、HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。”这里关键点在于指出,HashMap是在bucket中储存键对象和值对象,作为Map.Entry。这一点有助于理解获取对象的逻辑。如果你没有意识到这一点,或者错误的认为仅仅只在bucket中存储值的话,你将不会回答如何从HashMap中获取对象的逻辑。
3、利用get() 方法如何找到你想要的值,因为hashcode相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中,要找到你想要的值,去遍历bucket 对应的链表,而且HashMap在链表中存储的是键值对,这样就可以找到你想要的值,  找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象
4、HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。

当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。

因为HashMap的好处非常多,我曾经在电子商务的应用中使用HashMap作为缓存。因为金融领域非常多的运用Java,也出于性能的考虑,我们会经常用到HashMap和ConcurrentHashMap。你可以查看更多的关于HashMap的文章:

5、影响HashMap性能的有两个参数:初始容量(initialCapacity) 和加载因子(loadFactor)。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

6、元素数超过桶数,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。c++ 是选择质数表中的下一个指数。

7、重新调整HashMap大小存在什么问题 -》 多线程下的不安全。。

因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。  (理解上。。)

HashMap 和 HashTable 的区别


HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。 
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。 
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。



0 0
原创粉丝点击