hashmap是数组和链表组成的。而HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许重复的键。Map接口有两个基本的实现,HashMap和TreeMap。
因此其具有以下特点:
1) 快速存储 :比如当我们对hashmap进行get和put的时候速度非常快
2) 快速查找(时间复杂度o(1))当我们通过key去get一个value的时候时间复杂度非常的低,效率非常高
3) 可伸缩:1数组扩容,边长。2,单线列表如果长度超过8的话会变成红黑树
1.HashMap的工作原理
HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode(Hash值=(hashcode)^(hashcode >>> 16)),让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。
2.当两个对象的hashcode相同会发生什么
当hashcode相同,它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中,此时要获取值对象,HashMap会使用键对象的hashcode找到bucket位置,然后会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。
3.重新调整HashMap大小存在什么问题
首先要了解Hashmap底层原理扩容,Hashmap默认的负载因子大小为0.75,当map填满了75%的bucket时候,Hashmap将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。
这时如果有两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。有可肯会发生条件竞争,那么就会死循环。因此多线程的环境下不要使用HashMap。
4.为什么String, Interger这样的wrapper类适合作为键
因为String本质是final修饰的char数组,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。因此要保证不可变性