Hashmap

Hashmap是java面试中经常被问的问题,其重要性不言而喻。这不禁想起HashMap和Hashtable的比较:

  1. HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
  2. HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
  3. HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
  4. 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。HashMap不能保证随着时间的推移Map中的元素次序是不变的。
  5. HashMap几乎可以等价于Hashtable,那为什么用Hashmap呢?因为它快啊。Haspmap实现了Map接口,说起Map,我们就想起了put和get方法,那我们就讲一下Hashmap怎么在get方法上成为快男的。

性能是映射表的一个重要问,当我们应用get()方法,如果使用线性搜索的话,执行速度会很慢,这正是hashmap提高速度的地方。Hashmap使用了特殊的值,称作散列码,来取代对键的缓慢搜索。散列码是相对唯一的,用以代表对象的int值。hashcode()是根类Object的方法,因此所有Java对象都能产生散列码,Hashmap就是使用对象的hashcode进行快速查询,因此hashmap能显著提升性能。


数据结构的物理存储结构只有两种:顺序存储结构和链式存储结构(像栈,队列,树,图等是从逻辑结构去抽象的,映射到内存中,也这两种物理组织形式),而HashMap采用了链地址法,也就是数组+链表的方式。

既然我们了解了hashmap的基本数据结构,那hashmap的实现原理是怎样的呢?
HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对,Entry是HashMap中的一个静态内部类。 所以,HashMap的整体结构如下
HashMap结构图
HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象,HashMap是在bucket中储存键对象和值对象,作为Map.Entry。

HashMap由数组+链表组成的,这样的数据结构有什么用呢?
HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,急需要简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

当两个对象就算hashcode相同,但是它们可能并不相等,怎么解决呢?
这就是HashMap中的碰撞问题,了解了hashmap特殊的数据结构是不是恍然大悟啊。因为hashcode相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。

hashmap这样的数据结构,怎么使用get方法来获取值对象呢?
当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,然后获取值对象。当hashcode相同,它们的bucket位置可能有两个对象,我们就需要找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值