首先看一下 ArrayList、 Vector、 LinkedList 的结构图
接口与实现
类名 | 实现 | 继承 |
---|---|---|
ArrayList | List 、RandomAccess、Cloneable | AbstractList |
Vector | List 、RandomAccess、Cloneable | AbstractList |
LinkedList | List、Deque 、Cloneable | AbstractSequentieList -->AbstractList |
从上面表格可以看出来 ArrayList 、Vector 、 LinkedList 都是实现了List 接口方法,而List 继承了Collection 集合接口、统一了容器一些基本方法。
Collection
public interface Collection<E> extends Iterable<E> {
// 容器的数量
int size();
// 是否为空
boolean isEmpty();
// 是否包含一个对象
boolean contains(Object o);
//得到一个迭代器
Iterator<E> iterator();
// 转变为数组
<T> T[] toArray(T[] a);
// 简单的新增对象
boolean add(E e);
// 移除
boolean remove(Object o);
// 是否包含容器对象
boolean containsAll(Collection<?> c);
// 新增一个容器对象
boolean addAll(Collection<? extends E> c);
// 容器的交集
boolean retainAll(Collection<?> c);
void clear();
}
List接口
package java.util;
import java.util.function.UnaryOperator;
public interface List<E> extends Collection<E> {
// 这下面全是继承父类的方法
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
// 这个 JDK 1.8 里面的新特性 用来替换
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
// 用来排序 ,之前是可以 参数排序的方式
@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
// 下面这些方法就是List 本身的方法,用于在容器位置查询。
// 根据索引值得到对象
E get(int index);
// 新增指定位置的一个对象
E set(int index, E element);
// 新增一个指定位置的对象
void add(int index, E element);
// 移除某一个对象
E remove(int index);
// 查询是否存在某一个对象
int indexOf(Object o);
// 最后一个是否是某一个对象
int lastIndexOf(Object o);
// List Iterators
//
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
// 截取 当前对象
List<E> subList(int fromIndex, int toIndex);
//可分割迭代器(splitable iterator)
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.ORDERED);
}
}
ArrayList类
ArrayList 的内部实现其实就是一个数组 ,默认的存的是10 的一个大小,每次扩充就是创建一个新的数组,但是可以随机的访问,所以他的访问速度快一点。
package java.util;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import sun.misc.SharedSecrets;
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable // 用来实现序列化,就是把对象转为数据
{
private static final long serialVersionUID = 8683452581122892189L;
// 这里给ArrayList 定义一个初始化的储量值
private static final int DEFAULT_CAPACITY = 10;
// 开始空的数据
private static final Object[] EMPTY_ELEMENTDATA = {};
// 默认开始空的数据
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//用来存储数据的数组
transient Object[] elementData; s
/**
* 是定义ArrayList 里面对象的数量
*
* @serial
*/
private int size;
/**
*
* 用于新建一list容器
* @param initialCapacity 初始化容器的
*
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {// 初始化一个容器
this.elementData = new Object[initialCapacity]; // 数组的初始长度
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 默认
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //一个空数组
}
/**
*
* @param c 一个集合对象,可以通过这个构造方法对 set 、 linkedList ,Vector 进行装换,只要是继
* @throws NullPointerException 集合为空的时候为报空指针异常
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 对象进行拷贝 ,
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 新增arrayList
**/
public boolean add(E e){
// 扩容处理 当前size 大小 + 1
ensureCapacityIniernal(size + 1);
// 多一个位置存放对象
elementData[size++] =e ;
return true;
}
/**
* 拿到扩容的最大值
**/
private void ensureCapacityInternal(int minCapatity){
// 先判断数组是否为空
if(elementData == EMPTY_ELEMENTDATA){
// 和初始值比较最大值 当前的size + 1 和初始化的10 比较取最大值
minCapatity = Math.max(DEFAULT_CAPATITY,minCapatity);
}
ensureExplicitCapatity(minCapatity)
}
/**
*
**/
private void ensureExplicitCapatity(int minCapatity){
modCount++;//表示内部修改的次数
if(minCapatity - elementData.length > 0){// 如果需要扩容的数组长度大于数组长度就进行新增,否则就不进行扩容
grow(minCapatity);
}
}
/**
* 数据的扩充
**/
private void grow(int minCapatity){
int oldCapacity = elementData.length;
// 新的就是 长度为旧的长度扩容的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩展1.5 还是小于 minCapatity 就扩展为minCapacity
if(newCapacity - minCapatity < 0)
newCapacity = minCapacity;
// 对于数据进行扩容
elementData = Arrays.copyOf(elementData,newCapacity);
}
}
LinkedList类
LinkedList 是一个双向链表的节点结构,并且实现了双端队列的Deque 接口,实现了很多列队的方法,可以给前面的元素和最后的一个元素进行出栈,以及入栈。,所以可以再前后两端进行新增数据,并且每一次新增就是增加一个节点对象,所以新增的相比ArrayList 要快。但是获取要慢,因为是节点指向的所以要去拿数据就必须是从中间开始找。相比起来查询要慢。
public class LinkedList <E> extends AbstractSequentieList <E>
implements List<E>,Deque ,Cloneable,java.io.Serializable{
transient int size = 0; //长度
transient Node<E> first;// 第一个节点
transient Node<E> last; // 最后一个节点
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* 在链表后面添加元素
**/
void linkLast(E e) {
final Node<E> l = last; //最后一个节点
final Node<E> newNode = new Node<>(l, e, null); // 创建一个新的节点 ,前一个节点指向上一个节点,后面一个节点为null
last = newNode; // 把新节点设置为最后一个节点
if (l == null) // 如果最后一个节点为空
first = newNode; // 新节点就是最后一个节点
else
l.next = newNode; // 否则下一个节点链接到新节点
size++;// 数量增加
modCount++;
}
/**
* 得到首个元素
**/
public E getLast() {
final Node<E> l = last; //得到Node 对象
if (l == null)
throw new NoSuchElementException();
return l.item;
}
public E peek() {
final Node<E> f = first;//得到首个元素
return (f == null) ? null : f.item; //是null 就是null
}
/**
*删除节点
**/
public boolean remove(Object o) {
if (o == null) { //节点为null
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) { //删除内容为null的节点
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {//找对对应的节点
unlink(x);//删除节点
return true;
}
}
}
return false;
}
/**
* 删除节点的数量
**/
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item; // 获取这个节点 的元素
final Node<E> next = x.next; // 下一个节点
final Node<E> prev = x.prev; // 前一个节点
/**
* 如果前一个节点是空的就说我是第一节点,就把第一个后面一个节点放到一个上面
* 否则就是把自己节点的之前位置为下一个节点位置
**/
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
/**
* 如果下一个节点位置为空了 就是说我自己就是最后一个位置,
* 把前面一个设置为最后一个
* 否则就是下一个的前一个位置前节点指向前一个节点位置
**/
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
// 当前的节点位置的对象为空
x.item = null;
size--;// 长度
modCount++;
return element;
}
/**
*删除首个节点
**/
public E poll() {
final Node<E> f = first; //得到首个节点元素
return (f == null) ? null : unlinkFirst(f); //如果不是空 就是删除节点并返回
}
/**
*删除首个节点
**/
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item; // 得到节点的内容元素(用于返回)
final Node<E> next = f.next; // 和下一个节点
f.item = null; //把这个节点置空
f.next = null; // help GC 下一个节点置空
first = next; // 第一个节点等于下一个节点
if (next == null) // 如果下一个节点为空代表只有 一个元素,最有一个节点为空
last = null;
else
next.prev = null; // 就是本身这个节点上一个节点置空
size--; // 数量减1
modCount++; //修改增加
return element;// 返回节点内容
}
/**
*
* LinkedList 结构内部类
**/
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;
}
}
}
Vector 类
Vector 就是ArrayList 的一个线程安全的,在所有的方法上面加上一个synchronized 修饰符。所以Vector 的性能方面没有ArrayList 好。
总结
ArrayList :
- 可以随机访问
- 有序的查询效率高
- 添加需要复制数组,所以效率稍微低
LinkedList : - 按需分配空间,不需要预先分配空间。
- 不可以随机访问,按照所以访问效率比较低。
- 在两端添加和删除元素效率高
- 在中间插入效率低,但修改本身效率高。