java集合
注: 本文谈论的是基于
JDK1.8
版本
- ArrayList的底层数据结构:数组。
- LinkedList的底层数据结构:链表。既实现了
List
接口,又实现了Queue
接口,在使用的时候,如果我们把它当作List,就获取List的引用,如果我们把它当作Queue,就获取Queue的引用 - CopyOnWriteArrayList:和ArrayList基本一模一样,但它是线程安全的
- HashMap,ConcurrentHashMap 的底层数据结构: 数组+链表+红黑树实现,插入数据方式为尾插法,当链表长度超过阈值(8)时,并且数组长度超过64,将链表转换为红黑树,如果没超过64,只扩容(重新计算哈希值,复制数组过去),并不会转成红黑树,基于HashMap实现
- LinkedHashMap:底层是数组+链表+红黑树+双向链表
- TreeSet,TreeMap的底层数据结构:红黑树。
- HashSet的底层数据结构:数组+链表+红黑树。
List接口
- 元素有序
- 有索引
- 元素可以重复
ArrayList
- ArrayList的底层就是数组。
- 实现了Random Access接口,查询快;但是因为插入数据要更改其他元素位置,所以插入慢
- 如何扩容? 创建一个新的数组,再将旧数组复制进去,这样长度就增加了
- 当第一次add元素的时候,初始化默认大小为10,每次扩容为原来的1.5倍
LinkedList
- 底层是链表。链表增删快,故LinkedList常用来增删数据.
- 是一个双向链表,所以没有容量,没有扩容,直接在头尾添加即可.
CopyOnWriteArrayList
- 和ArrayList基本一模一样,但它是线程安全的
- 适合多读少写的场景
- 任何对array在结构上有所改变的操作(add、remove、clear等),CopyOnWriterArrayList都会copy现有的数据,再在copy的数据上修改,这样就不会影响COWIterator中的数据了,不会抛ConcurrentModificationException异常(对set,add没有作用,因为set,add本来就要加锁),修改完成之后改变原有数据的引用即可。
- 读操作不加锁,写操作加锁,在进行add,set等操作时,会通过ReentrantLock进行加锁
- 缺点:
- 1.复制的数组会消耗内存
- 2.不能读取实时性的数据
- 3.会产生大量的对象
Set接口
使用了HashMap的key,value为空
- 元素无序
- 没有索引
- 元素不能重复
Collection遍历删除元素
1.普通for循环:注意每次删除之后索引要--
2.Iterator遍历:不过要使用Iterator
类中的remove
方法,如果用List
中的remove
方法会报错
3.增强for循环foreach
:不能删除,强制用List中的remove方法会报错.foreach循环实际上是生成器
Map接口
HashMap
- 键值对
- 无序,不支持排序
- 采用哈希算法定位元素,计算公式为:通过hashCode()的高16位
异或
低16位(h = k.hashCode()) ^ (h >>> 16)得到h,然后h&(length - 1)
,k是键,length为数组长度.所以length要设置2的n次方,这样可以散列的更均匀,而且计算下标方便,并且扩容的时候可以让原数组处的链表长度减小一半(理想情况下) - key,value可以存null
- value可以重复,key重复会覆盖value
- 数组默认大小是16,存储的数据超过容量的75%开始
扩容
.默认大小和负载因子可以自定义.扩容后容量是之前的两倍 - 多线程使用时,
扩容
会死循环,要用ConcurrentHashMap
ConcurrentHashMap
- 线程安全的HashMap,但是key,value不允许为
null
- 相比Hashmap多了锁对象
segment
- put基本流程
- 通过CAS+synchronized加锁(jdk1.8),只需要锁住数组中有链表元素的头部位置;1.7是分段加锁
- 1.如果没有hash冲突就直接通过CAS插入
- 2.如果有hash冲突或者CAS操作失败,说明存在并发情况,使用synchronized加锁
- 3.如果插入成功就调用addCount()方法统计size,并且检查是否需要扩容
LinkedHashMap
- 比HashMap多维护了一个链表用来记录顺序
- LinkedHashMap 可以通过构造参数 accessOrder 来指定双向链表是否在元素被访问后改变其在双向链表中的位置。
- LRU实现:插入数据后对调用afterNodeInsertion,afterNodeInsertion()方法中会调用removeEldestEntry,如果removeEldestEntry(first)返回true,按照LRU策略,那么会删除头节点(注意这里删除的是头节点!!!所以每次访问元素或者插入元素之后都要将该元素放到链表末尾)。这个也是实现LRU的关键点!!!!!
HashTable
为了解决哈希冲突.不建议使用,完全可以用ConcurrentHashMap替代
哈希表可以用来高效率解决元素不可重复这个问题,其本质就是:数组+链表+红黑树。
所以如果新建了一个对象,需要重写hashCode方法和equals方法
- key,value都不可为null
- 线程安全,所有方法上都加了
synchronized
关键字 - 哈希值就有点类似于数组中的索引,因为哈希值不同其元素必定不同
- 如果没有相同的哈希值,直接添加进集合
- 如果有相同的哈希值,再用equals方法比较内容是否一样
- 扩容
- 哈希表中数组默认长度11,如果数组中的元素超过了75%就开始扩容
- 扩容时,capacity=2*capacity+1
- 如果链表元素数量超过8,就将链表重构成红黑树。
SortedMap接口
- 有序
- 支持排序
- 不可存null
- 查找较慢
- value可以重复
- 采用红黑树排序,可以调用Comparator类型的构造方法进行定制排序
TreeMap
是它的实现类,继承体系 Map -> SortMap -> NavigbleMap -> TreeMap
你要是觉得写的还不错,就点个关注,可以评论区留下足迹,以后方便查看.
你要是觉得写的很辣鸡,评论区欢迎来对线!
欢迎转载!