刚才在看视频的时候看到一个人问为啥hashmap这么重要,确实是个好问题,我们在讨论数据结构链表、数组、二叉树的时候,都是想把它们应用到真实的场景中,用来提高工作效率,hashmap就是一个很典型很经典的一个应用,jdk1.7中集成了数组与链表,jdk1.8中集成了数组、链表和红黑树,我们在讨论算法和数据结构的时候,更加在意的是这些算法和数据结构怎么落地,或者说应用到我们实际的工作与生活中让生活变得更美好,我想这就是计算机、数据结构、hashmap存在的意义吧。

Hashmap的内部实现

HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个k-v键值对
图片说明
HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好
HashMap有4个构造器,其他构造器如果用户没有传入initialCapacity 和loadFactor这两个参数,会使用默认值
initialCapacity默认为16,loadFactory默认为0.75

jdk1.7与jdk1.8中hashmap的差异

1)jdk8中会将链表转变为红黑树
2)新节点插入链表的顺序不相同(7是插入头节点,jdk8因为要遍历链表把链表变为红黑树所以用尾***r>3)hash算法简化
4)resize的逻辑修改

附上两道经典的面试题:

HashMap和Hashtable有什么区别?

1、继承的父类不同
Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。
2、线程安全性不同
Hashtable 中的方法是Synchronize的,而HashMap中的方法在缺省情况下是非Synchronize的。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步,但使用HashMap时就必须要自己增加同步处理
3、是否提供contains方法
Hashtable保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。
4、key和value是否允许null值
Hashtable中,key和value都不允许出现null值。但是如果在Hashtable中有类似put(null,null)的操作,编译同样可以通过,因为key和value都是Object类型,但运行时会抛出NullPointerException异常,这是JDK的规范规定的。
HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
5、两个遍历方式的内部实现上不同
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
6、hash值不同
HashTable直接使用对象的hashCode。而HashMap重新计算hash值
7、内部实现使用的数组初始化和扩容方式不同
HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

为什么重写equals还要重写hashcode

尽管我们在进行get和put操作的时候,使用的key从逻辑上讲是等值的(通过equals比较是相等的),但由于没有重写hashCode方法,所以put操作时,key(hashcode1)-->hash-->indexFor-->最终索引位置 ,而通过key取出value的时候 key(hashcode1)-->hash-->indexFor-->最终索引位置,由于hashcode1不等于hashcode2,导致没有定位到一个数组位置而返回逻辑上错误的值null(也有可能碰巧定位到一个数组位置,但是也会判断其entry的hash值是否相等,上面get方法中有提到。)