目录
参考书:《很好-Java程序性能优化.pdf》
List有三种:ArrayList、Vector和LinkedList.我们只讨论Arrylist和LinkedList
以下研究都是在jdk1.7
6.1.ArrayList
讨论:组成,初始化大小,怎么扩容,怎么插入、删除
1.组成:
内部封装了对数组的操作,对他进行添加、删除、插入都是对数组的操作.
代码:
public class ArrayList<E> { private static final int DEFAULT_CAPACITY = 10;//默认容量 private transient Object[] elementData;//数组 private int size;//数组实际存储大小,并不是数组的大小 } |
原文:https://blog.csdn.net/lan861698789/article/details/81323634
2.怎么扩容
如果不指定容量,那么默认容量大小就是10。
每次对数组进行添加、插入都需要判断 内部数组是否有足够的空间,没有则扩容。
扩容大小为原来大小的1.5倍。
以添加为例,代码:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) {//判断是否需要扩容 int oldCapacity = elementData.length;//现在容量大小 int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容原来容量的1.5倍 if (newCapacity - minCapacity < 0) //如果扩容后还是不能满足,则当前容量设置为 需要插入的大小 newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);//数组的扩容 } } |
合理的数组大小,有助于减少数组扩容的次数,从而提高系统性能.
原文:https://blog.csdn.net/lan861698789/article/details/81323634
3.新增
新增是加到数组的最后一个。
代码:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } |
原理:
a.扩容一个长度
b.将数组的最后一位赋值为要增加的元素
原文:https://blog.csdn.net/lan861698789/article/details/81323634
4.插入
任意位置添加元素.
代码:
public void add(int index, E element) { ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } |
原理:
a.扩容一个长度
b.把从插入位置的元素往后移一位
c.赋值要插入的元素
原文:https://blog.csdn.net/lan861698789/article/details/81323634
5、插入数组
和插入一个元素区别不大。
代码:
public boolean addAll(int index, Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved);//部分元素整体右移
System.arraycopy(a, 0, elementData, index, numNew);//复制要插入的元素数组 size += numNew; return numNew != 0; }
|
原理:
原文:https://blog.csdn.net/lan861698789/article/details/81323634
6、删除
代码:
public E remove(int index) { modCount++; E oldValue = elementData(index);//获取要删除的元素
int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved);//往左移 elementData[--size] = null; // clear to let GC do its work.最后一位值赋值为空
return oldValue; } |
原文:https://blog.csdn.net/lan861698789/article/details/81323634
6.2.LinkedList
讨论:组成,初始化大小,怎么扩容,怎么插入、删除
1.组成:
使用了双向链表的数据结构。
不需要扩容。
linkedlist只会存这个容器的长度,首、尾元素。
然后每个元素里面包含了该元素的当前值,前一个元素,后一个元素。
代码
public class LinkedList<E> { transient int size = 0; transient Node<E> first;//头节点 transient Node<E> last;//尾节点 }
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; } } |
原文:https://blog.csdn.net/lan861698789/article/details/81323634
原文:https://blog.csdn.net/lan861698789/article/details/81323634
2.新增
新增是往最后插的。
代码:
void linkLast(E e) { final Node<E> l = last;//原来的last赋值 final Node<E> newNode = new Node<>(l, e, null);//构建新节点,这里把原来的last赋值给了新节点的pre last = newNode;//last赋值 l.next = newNode; size++; modCount++; } |
原理:
构建新节点,把新节点的prev指向原来的最后一个节点;
把原来最后一个节点的next指向新节点。
原文:https://blog.csdn.net/lan861698789/article/details/81323634
3.插入
插入任一点
代码:
public void add(int index, E element) { linkBefore(element, node(index)); } //找出该位置的节点值 Node<E> node(int index) { //做了一个size判断。是从头循环开始找,还是从尾循环开始找 if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } } //插入 void linkBefore(E e, Node<E> succ) { final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; pred.next = newNode; size++; modCount++; } |
原理:
从首or尾节点循环遍历到该index位置,找出要插入位置的值
再进行 各种赋值。
原文:https://blog.csdn.net/lan861698789/article/details/81323634
4.删除
删除任意位置的值
代码:
public E remove(int index) { return unlink(node(index)); } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> prev = x.prev; final Node<E> next = x.next; //前面元素的next 重新赋值 prev.next = next; x.prev = null; //后面元素的prev 重新赋值 next.prev = prev; x.next = null; //当前元素置为空 x.item = null; size--; modCount++; return element; } |
原理:
从首or尾节点循环遍历到该index位置,找出要插入位置的值
再进行 各种赋值。
原文:https://blog.csdn.net/lan861698789/article/details/81323634
6.3两种List使用对比
如果是经常要进行任意位置的插入,建议使用linkedList;不使用arrayList,是因为要频繁扩容。
如果是经常要进行任意位置的查找,建议使用arrayList;不使用linkedlist,是因为要循环查找。