ArrayList LinkedList 解析

首先看一下 ArrayList、 Vector、 LinkedList 的结构图
在这里插入图片描述

接口与实现

类名实现继承
ArrayListList 、RandomAccess、CloneableAbstractList
VectorList 、RandomAccess、CloneableAbstractList
LinkedListList、Deque 、CloneableAbstractSequentieList -->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 :
  • 按需分配空间,不需要预先分配空间。
  • 不可以随机访问,按照所以访问效率比较低。
  • 在两端添加和删除元素效率高
  • 在中间插入效率低,但修改本身效率高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值