HashMap
HashMap是基于哈希表的Map接口的非同步实现。实现HashMap对数据的操作,允许有一个null键,多个null值。
HashMap底层就是一个数组结构,数组中的每一项又是一个链表。数组+链表结构,新建一个HashMap的时候,就会初始化一个数组。Entry就是数组中的元素,每个Entry其实就是一个key-value的键值对,它持有一个指向下一个元素的引用,这就构成了链表,HashMap底层将key-value当成一个整体来处理,这个整体就是一个Entry对象。HashMap底层采用一个Entry【】数组来保存所有的key-value键值对,当需要存储一个Entry对象时,会根据hash算法来决定在其数组中的位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry对象时,也会根据hash算法找到其在数组中的存储位置, 在根据equals方法从该位置上的链表中取出Entry;
put:(key-value)方法是HashMap中最重要的方法,使用HashMap最主要使用的就是put,get两个方法。
判断键值对数组table[i]是否为空或者为null,否则执行resize()进行扩容;
根据键值key计算hash值得到插入的数组索引 i ,如果table[i] == null ,直接新建节点添加即可,转入6,如果table[i] 不为空,则转向3;
判断table[i] 的首个元素是否和key一样,如果相同(hashCode和equals)直接覆盖value,否则转向4;
判断table[i] 是否为treeNode,即table[i]是否为红黑树,如果是红黑树,则直接插入键值对,否则转向5;
遍历table[i] ,判断链表长度是否大于8,大于8的话把链表转换成红黑树,进行插入操作,否则进行链表插入操作;便利时遇到相同key直接覆盖value;
插入成功后,判断实际存在的键值对数量size是否超过了threshold,如果超过,则扩容;
也可参考HashSetput过程:
https://www.jianshu.com/p/419a448414da
get方法取值过程:
int hash = key.hashCode();
int index = hash%Entry[].length;
指定key通过hash函数得到key的hash值;
调用内部方法getNode(),得到桶号(一般为hash值对桶数求摸);
比较桶的内部元素是否和key相等,如不相等,则没有找到,相等,则取出相等记录的value;
如果得到key所在桶的头结点恰好是红黑树节点,就调用红黑树节点的getTreeNode()方法,否则就遍历链表节点。getTreeNode()方法通过调用树形节点的find()方法进行查找。由于之前添加时已经保证这个树是有序的,因此查找时基本就是折半查找,效率高;
如果对比节点的哈希值和要查找的哈希值相等,就会判断key是否相等,相等就直接返回;不相等就从子树中递归查找;
HashMap中直接地址用hash函数生成,冲突用比较函数解决。如果每个桶内部只有一个元素,那么查找的时候只有一次比较。当许多桶内没有值得时候,许多查询就会更快
addEntry方法
- 添加新元素前,判断是否需要对map的数组进行扩容,如果需要扩容,则扩容多大?
- 对于新增key-value键值对,如果可以的hash值相同,则构造单向列表;
TreeMap
实现了SortedMap接口,是一个有序的集合,是一个红黑树接口,每个key-vlaue作为红黑树的节点,没有指定顺序则是根据key执行自然排序。默认自然排序
- 继承了AbstractMap类,实现了接口
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
可以自然排序,可以定制排序,Entry root = null 红黑树的根节点;size存放键值对的数量。
- 自然排序:所有的key必须实现Comparable接口,所有的key都是同一类的对象;
-
定制排序:创建TreeMap对象传入一个Comparator对象,改对象负责key进行排序,采用定制排序不要去key实现comparable接口。
- 自定义排序时候,需要将Comparator对象传进集合中当作参数,进而进行排序。Comparator的对象也需要传进两个实体类对象,进行两两比较。,return 比较的结果,如果是正数就是从下到大排序,等于0说明两个数的一摸一样,直接去重,如果是负数,说明一个数小,此刻return返回一个负数,排序的是时候么就是按照倒序排序的。
- 主要方法:
put():
get():根据不同的排序比较方法定位需要的数据,检索速度时间复杂度为O(log(n));
remove():
TreeMap默认是自然排序,没有查找方法;无需遍历
- 红黑树
是一个更高效检索二叉树,每个节点只能是红色或者黑色;根节点永远是黑色;所有叶子的子节点都是空节点,并且都是黑色;每个红色节点的两个子节点都是黑色,没有连续的红色节点;从人一个节点到其子树中的每个叶子节点的路径中所包含相同数量的黑色节点。
HashMap和TreeMap比较
(1)HashMap:适用于在Map中插入、删除和定位元素。 默认乱序
(2)Treemap:适用于按自然顺序或自定义顺序遍历键(key)。 默认自然排序,如果插入的是基本类型,按照 大小排序。如果是引用类型,则按照插入顺序
(3)HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap.**
(4)HashMap 非线程安全 TreeMap 非线程安全
(5)HashMap的结果是没有排序的,而TreeMap输出的结果是排好序的。
在HashMap中通过get()来获取value,通过put()来插入value,ContainsKey()则用来检验对象是否已经存在。可以看出,和ArrayList的操作相比,HashMap除了通过key索引其内容之外,别的方面差异并不大。
Treemap的方法是在hashmap的基础上进行补充的