好了到这我自己认为比较重要的方法源码就都列出来的,所以将ArrayList的介绍就告一段落了,那么到这我就只有一个疑问就是关于elementData在首次add时加载jar或者路径是做什么用的,如果您知道,请评论在下面,非常谢谢您
总结一下ArrayList,我们在分析源码的时候,除了在首次add时会添加路径之类的信息会设计到其他类的同步加载方法,但是本类的方法并没有涉及同步,所以ArrayList并不是线程安全的,并且他是懒加载的,首次默认初始化并不会就初始化为初始化容量,而是在之后才会初始化为初始化容量,这个类的核心就是System.arraycopy方法,所以以后我们在操作数组移动的时候,我们也可以使用这个native方法使得程序更加的快速准确,在add和get的时候是相当迅速而直接的,就是将制定位置元素后移并在此位置上插入元素,所以ArrayList的增加和查询是很迅速的,但是我们也需要注意,当ArrayList的元素满的时候他是创建新数组进行copy的,所以当ArrayList的元素相当大的时候,这无疑是一个恐怖的事情,所以ArrayList并不适合存储很多元素
LinkedList可以先参考一下这篇关于链表的文章,如果你有了解一点就可以不用看了 : 链表
这是一个链表实现的List的实现类,对于ArrayList这个类要并不存在扩容copy的问题,如果你了解一点链表内容就会知道,增加元素在链表中无非就是改变引用的事情,所以它并没有这样的问题,好了让我们直接上源码吧
依旧先看一下他的成员属性
//元素个数 transient int size = 0; //头节点 transient Node<E> first; //尾节点 transient Node<E> last;
transient代表不会被序列化,那么Node是啥东西,看一下源码
private static class Node<E> { E item; //本元素值 Node<E> next; //前元素指向 Node<E> prev; //后元素指向 Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
从中可以LinkedList实现是一个双链表,我们接下来看看他的初始化方法的实现
public LinkedList() { }
空参构造什么都没做,接下来看其他的初始化方法
public LinkedList(Collection<? extends E> c) { this(); addAll(c); }那么这个有参的构造方法其实主要逻辑是addAll方法,我暂时先不说这个方法,那么我们先来看看其他的核心实现方法
add
源码如下
public boolean add(E e) { linkLast(e); //添加到链表最后面 return true; } void linkLast(E e) { //将最后一个元素引用保留 final Node<E> l = last; //创建一个新的元素根据传入的add参数,新的对象的前一个元素的引用 //就是之前的最后一个元素 final Node<E> newNode = new Node<>(l, e, null); //将最后的元素指针指向新元素 last = newNode; //如果之前的尾元素是空的代表是空链表, if (l == null) //即首尾都是此元素 first = newNode; else //就不是空链表,那么倒数第二个的元素的下一个元素就是新元素 l.next = newNode; size++; modCount++; }
还有一种是根据index位置插入的
public void add(int index, E element) { //是否越界 checkPositionIndex(index); //如果index等于元素个数 if (index == size) //那么就添加到尾部 linkLast(element); else //否则就按位置添加 //node方法,传入index,返回指定元素索引处的(非空)节点 linkBefore(element, node(index)); } void linkBefore(E e, Node<E> succ) { //已经确保了succ不为空,在上面node方法中确保的 //取出指定index索引上的元素的前一个元素引用 final Node<E> pred = succ.prev; //创建新的元素,新元素的前一个元素就是目前指定index上的元素的前一个元素 //下一个元素是index上面的元素 final Node<E> newNode = new Node<>(pred, e, succ); //将指定索引位置的原元素的前指针指向新元素 succ.prev = newNode; //如果是在头部添加,那么当前元素的前一个元素肯定为空 if (pred == null) //然后新元素就成为了头元素 first = newNode; else //否则就将index-1位置的元素的后指针指向新元素 pred.next = newNode; size++; modCount++; }如果你熟悉链表,那么上面的代码就很简单就能理解了,如果看不懂,可以自己画一下图,瞬间明白
addAll