前言
文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…
种一棵树最好的时间是十年前,其次是现在
絮叨
前面2篇的基础,大家还是好好学习一下,下面是链接
🔥史上最全的Java容器集合之ArrayList(源码解读)
今天讲Vector和LinkedList(顺便提一下,如果是零基础的不建议来,有过半年工作经验的跟着我一起把这些过一遍的话,对你的帮助是非常大的)
Vector 源码分析
其实Vector要讲的东西不多了,因为它和ArrayList的代码很像,就是再每个方法上加了锁,如下图
因为大部分和前面差不多,我来说说不同的点吧
看图上面的 这个是Vetor和ArrayList不同的另一个点 它的增长因子是可以自己定义的。我们来看grow方法
这段代码是扩容代码,可以看如果定义了曾长因子就每次扩容增长因子,不然就是扩容2倍
其他的增删改查,我就不说了,自己也没细看,但是底层是数组,所以大多数是相同了 只是加了一个synchronized锁
这边提一下其实ArrayList也可以变成线程安全
如果想要ArrayList实现同步,可以使用Collections的方法:List list=Collections.synchronizedList(new ArrayList(...));,就可以实现同步了
LinkedList源码分析
概念
- LinkedList是基于链表实现的,所以先讲解一下什么是链表。链表原先是C/C++的概念,是一种线性的存储结构,意思是将要存储的数据存在一个存储单元里面,这个存储单元里面除了存放有待存储的数据以外,还存储有其下一个存储单元的地址(下一个存储单元的地址是必要的,有些存储结构还存放有其前一个存储单元的地址),每次查找数据的时候,通过某个存储单元中的下一个存储单元的地址寻找其后面的那个存储单元。
- 理解:
- LinkedList是一个双向链表
- 也就是说list中的每个元素,在存储自身值之外,还额外存储了其前一个和后一个元素的地址,所以 也就可以很方便地根据当前元素获取到其前后的元素
- 链表的尾部元素的后一个节点是链表的头节点;而链表的头结点前一个节点则是则是链表的尾节点(是不是有点像贪吃蛇最后 头吃到自己尾巴的样子,脑补下)
- 既然是一个双向链表,那么必然有一个基本的存储单元,让我们来看LinkedList的最基础的存储单元。
对于单项链表 自己手撕了一个,有兴趣的可以去看看
继承结构和层次关系
从这个图来对 和底层是数组结构的2个集合的区别 少实现了一个随机访问的RandomAccess接口 多实现了一个Deque接口 所以linkedList并不具备随机访问的功能,它也必须一个个去遍历,结论是: ArrayList用for循环遍历比iterator迭代器遍历快,LinkedList用iterator迭代器遍历比for循环遍历
还有可以看出LinkedList与ArrayList的另外不同之处,ArrayList直接继承自AbstractList,而LinkedList继承自AbstractSequentialList,然后再继承自AbstractList。另外,LinkedList还实现了Dequeu接口,双端队列。
Deque双端队列
Deque 双端队列,这个之前没讲过,唉 一个个坑,自己填吧
双端队列(deque,全名double-ended queue),是一种具有队列和栈的性质的数据结构。队列是一个有序列表,可以用数组或是链表来实现。
双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。双端队列可以在队列任意一端入队和出队,
遵循先入先出的原则:
- 先存入队列的数据,要先取出。
- 后存入的要后取出
来看看队列的方法吧
- add和offer 都表示插入 区别是一个失败会报错,一个失败返回false
- remove 和 poll 都表示删除 都是删除成功返回队首元素 当队列为空时它会抛出异常。remove失败的话会报错 poll返回null
- element peek 返回队首元素,但是不删除队首元素,element 当队列为空时它会抛出异常。peek返回null
总结一下 其实队列很简单,特别像这种简单 只有三个操作 加入 删除 查看 且全部是针对队首的操作。
接下来我们看看deque吧
有点多 哈哈 其实操作也差不多,队列就是只能操作队首,双向队列就是可以操作队首和队尾