集合容器概述
什么是集合
集合就是一个存放数据的容器,集合存放的都是对象的引用,而不是对象本身。集合主要分为set、list和map。
集合和数组的区别
- 数组是固定长度的;集合时可变长度的;
- 数组可以存储基本数据类型,也可以存储引用数据类型,集合只能存储引用数据类型;
- 数组存储的元素必须是同一数据类型,集合存储的对象可以是不同数据类型。
集合结构
collection(单列集合)
list(有序,可重复)
- Vector:数组结构,线程安全
- ArrayList:数组结构,非线程安全,实现了RandomAccess接口,查找快,增删慢
- LinkedList:链表结构,非线程安全,线性的数据存储方式,需要移动指针从前往后一次查找,增删快,查找慢
Set(无序,唯一)
- HashSet:哈希表结构,无序、唯一,基于HashMap实现的,底层采用HashMap来保存元素
- TreeSet:红黑树结构,有序、唯一
- LinkedHashSet:哈希表加链表结构
Map(双列集合)
- HashTable:哈希表结构,线程安全
- HashMap:哈希表结构,非线程安全:jdk1.7和jdk1.8做了一个很大的改变。1.7之前是数组加链表,它的数据节点是一个Entry节点,是HashMap里边实现的一个静态内部类,而且它的数据插入过程使用的是头插法,但是使用头插法会造成一个问题,就是它在扩容的时候,里边有一个resize方法,它又调用了一个transfer方法,这个方法会把里边的一些Entry进行一个rehash,在这个过程中,可能会造成一个链表的循环,可能在下一个get的时候出现一个死循环的情况,而且它没有加锁,也有可能多个线程并发的情况下,不能保证数据是一个安全的;jdk1.8之后结构变成了数组加链表和红黑树的结构,把原来的Entry节点变成了一个Node节点,它的数据插入方法是尾插法,整个put过程也做了一个优化,就是之前hashmap处理冲突单纯的使用链表进行连接,1.8之后就是当一散列值中数量超过八个之后就会将链表转化为红黑树进行存储(提高数据的检索性能)
- TreeMap:红黑树结构
- LinkedHashMap:哈希表和链表结构
什么是Hash算法
哈希算法是指将任意长度的二进制映射为固定长度的较小的二进制值,这个较小的二进制值叫做哈希值、
什么是链表
链表是可以将物理地址上下不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查等功能。链表大致分为单链表和双向链表:单链表每个节点包含两部分,一部分存放数据变量的data,另一部分是指向下一节点的指针;双向链表除了包含单链表的部分,还增加的pre前一个节点的指针。
HashMap的实现原理
HashMap是基于Hash算法实现的,当我们往HashMap中put元素时,利用key的hashcode重新hash计算出当前对象的元素在数组中的下标,存储时如果出现hash值相同的key,则会去判断内容是否相同,如果key内容相同,则覆盖原始值,如果key内容不同(出现冲突),则将当前的key-value放入链表中;获取时,直接找到hash值对应的下标,再进一步判断key内容是否相同,从而找到对应的值。
HashMap扩容机制
如果创建集合时没有设置capacity,那么它默认是16,负载因子0.75,它会计算出一个threshold也就是一个阈值,当在调用put方法的时候会先通过hash算法得到hash值,判断Node数组table是否为null或长度是否为0,如果是就会调用resize方法对table进行扩容,容量规则是2的幂次。
HashMap是怎么解决hash冲突的
首先在解决这个问题之前,我们要了解什么是哈希和哈希冲突,Hash一般翻译为“散列”,也有直接音译为“哈希”的,Hash就是只使用Hash算法将任意长度的二进制映射为固定长度的较小的二进制值,这个较小的二进制值叫做哈希值;当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞也就是哈希冲突。
可以使用链表法,将相同hash值的对象组织成一个链表放在hash值对应的槽位;
可以使用开放地址法,通过一个探测算法,当某个槽位已经被占据的情况下继续查找下一个可以使用的槽位。