前言
上一篇文章讲了ArrayList和Vector,这两者是基于数组,还是比较好理解的,LinkedList是基于链表实现的,所以适合有数据结构基础的同学阅读~ 本文所有代码都是基于JDK8的
LinkedList
从结构上,我们还看到了LinkedList实现了Deque接口,因此,我们可以操作LinkedList像操作队列和栈一样,LinkedList的底层是链表,先来看一下节点的定义:
从节点的定义可以看出LinkedList是双向链表,学过数据结构的同学应该对链表的结构还是比较熟悉的,这里就不展开说了。LinkedList的属性只有三个:头尾节点、以及size:
构造方法
LinkedList有两个构造方法,如下图:
分别是空构造方法,和一个根据其他容器添加元素的构造方法
Link相关方法
Link相关方法都是private或者default的,也就是说在外部并不能访问到。之所以将Link相关方法写进来是因为Link相关方法对我们学习链表还是非常有帮助的,并且removeLast、removeFirst、addLast、addFirst、add等方法其实都是调用了Link相关方法。Link相关方法分别有:
- void linkFirst(E e) :在头节点前插入一个元素
- void linkLast(E e) :在尾节点后插入一个元素
- void linkBefore(E e, Node succ) :在指定节点前插入一个元素
- E unlinkFirst(Node f) :删除头节点
- E unlinkLast(Node l) : 删除尾节点
- E unlink(Node x) :删除指定节点
这里方法比较多,我们只挑几个看看:
- linkFirst方法:
- 实现步骤:
1、创建新节点,新节点的last指向头节点
2、头结点指向新建节点
3、判断原链表是否为空,如果为空将尾节点指向头结点,如果不为空将旧头节点指向新头节点 - linkBefore方法:
- 在指定节点前插入节点的实现步骤也类似,多了一步前节点prev的指向
- unlink方法
- 删除一个节点分为好几种情况:
- 前节点为空,后节点不为空:此时为头节点,将头节点指向后节点,然后将后节点的前节点置空。
- 前节点不为空,后节点为空:此时为尾节点,将前节点指向后节点(null),同时成为尾节点
- 前节点不为空,后节点不为空:将前后节点分别指向对方
Link相关方法真的写的非常的简洁!非常值得我们学习
add方法
add方法其实也就是调用了linkLast方法,看下LinkLast方法:
和linkFirst方法非常的像啊,有木有~
remove方法
- 先看一下remove(Object o)方法,从链表中删除指定元素
- remove方法的思想也很简单,先判断o是否为空,因为如果o为空则不能使用equals来比较。然后对链表进行遍历。注意,这里比较的是两个对象的地址!使用的是object的equals方法。
- 再看一下remove(int index)方法,从链表中删除指定下标元素
- checkElementIndex方法是检查index是否越界,这里的node(int index)方法比较重要,这个方法的作用是从链表中找到指定下标的节点,来看一下:
if (index < (size >> 1))
这句话是用于判断所处节点是靠近头节点还是尾节点,这样搜索的效率更高一些,然后就是进行for循环直到指定下标,返回指定下标的节点。
push、pop方法
push、pop方法分别调用了addFirst和removeFirst方法,addFirst方法中调用了linkFirst方法,removeFirst方法中调用了unlinkFirst方法。所以这也是我为什么一开始就先将link相关方法的原因,因为link方法虽然在外部不能直接使用,但是有关链表的删除、插入操作都是通过调用link相关方法来实现的。对link相关方法还不了解的同学可以翻到最前面复习一下~
set方法
首先检查下标是否越界,然后调用node(index)方法找到对应下标的节点,然后设置新值,返回旧值。
总结
关于三大集合的源码到这里就讲完了,代码感觉也不是很难,只要仔细阅读一定可以看懂,下面做一个总结:
- ArrayList:
底层实现是数组
ArrayList的默认初始化容量是10,每次扩容时候增加原先容量的一半,也就是变为原来的1.5倍
在增删时候,需要数组的拷贝复制(navite 方法由C/C++实现)
- LinkedList:
底层实现是双向链表[双向链表方便实现往前遍历]
- Vector:
底层是数组,现在已少用,被ArrayList替代,原因有两个:
Vector所有方法都是同步,有性能损失。
Vector初始length是10 超过length时 以100%比率增长,相比于ArrayList更多消耗内存。
因此查询多的时候用ArrayList,增删多用LinkedList