【Java底层】-List集合


#####1. Collection
Iterable 接口与 Map 接口在 Java 体系中占主要地位,基本上所有的数据结构都是基于这个两个接口,一个是线性可迭代的一个是哈希表。

通过上图看出,Collection 接口作为集合体系的父接口,Map 作为哈希表体系的接口。

最主要的集合 Collection 源码提供方法:


public interface Collection<E> extends Iterable<E> {
    int size();  // 集合大小
    boolean isEmpty(); // 是否为空
    boolean contains(Object o); // 是否包含某个元素
    Iterator<E> iterator(); // 返回迭代器
    Object[] toArray(); // 返回 Object 数组
    <T> T[] toArray(T[] a); // 返回指定泛型的数组
    boolean add(E e); // 添加一个元素,返回是否添加成功
    boolean remove(Object o); // 移除一个元素,返回是否添加成功
    boolean containsAll(Collection<?> c); // 是否包含另一个集合
    boolean addAll(Collection<? extends E> c); // 将另一个集合添加到当前集合
    boolean removeAll(Collection<?> c); // 移除当前集合的元素,返回集合是否被修改过
    default boolean removeIf(Predicate<? super E> filter); // 根据添加移除元素
    boolean retainAll(Collection<?> c); // 仅保留存在于给定集合的元素,返回集合是否被修改过
    void clear(); // 清空集合
    boolean equals(Object o);  // 判断是否相等
    int hashCode();	 // 返回hash值
}

#####2. List

  1. 存储的数据特点:存储有序的、可重复的数据。
  2. 常用的实现类:
  • Collection接口:单列集合,用来存储一个一个的对象
  • List接口:存储序的、可重复的数据。 -->“动态”数组,替换原的数组
  • ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储,随着元素的增加而动态扩容
  • LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储,随着元素的增加而不断向链表的后端增加结点

######2.1 List接口

#List方法
A:添加功能
  boolean add(E e):向集合的尾部添加一个元素
* void add(int index, E element):在指定位置添加元素
  boolean addAll(Collection<? extends E> c):在集合中尾部添加一个集合。
* boolean addAll(int index, Collection<? extends E> c);// 在集合指定位置添加一个集合。

B:删除功能
  void clear():删除集合中的所有元素
* E remove(int index):删除集合指定位置的元素,并把删除的元素返回
  boolean remove(Object o):删除集合中指定的元素
  boolean removeAll(Collection<?> c):删除两个集合的交集 。
* default void replaceAll(UnaryOperator<E> operator) // 将集合中的元素特换成指定元素

C:修改功能
  void clear(); // 清空集合元素
   E set(int index, E element):把指定索引位置的元素修改为指定的值,返回修改前的值。

D:获取功能
*   E get(int index):获取指定位置的元素
* int indexOf(Object o);// 获取元素在集合中首次出现的位置,获取不到返回 -1
* int lastIndexOf(Object o);// 获取元素在集合中最后出现的位置,获取不到返回 -1
* List<E> subList(int fromIndex, int toIndex);// 截取指定区间位置内的集合

E:迭代器
   Iterator iterator():获取集合中每一个元素。
*  ListIterator<E> listIterator(int index); // 获取集合从特定位置开始的每个元素

F:判断功能
  boolean isEmpty():判断集合是否为空:size==0
  boolean contains(Object o):判断集合中是否存在指定的元素。
  boolean containsAll(Collection<?> c):判断集合C是否为当前集合的子集。
*  boolean retainAll(Collection<?> c); // 求两个集合的交集,并将交集赋值给当前集合,若集合有变化则返回true,若两集合相等则返回false
  boolean equals(Object o);// 判断两个集合是否相等:集合长度、元素、元素位置

G:数组功能
  int hashCode();
  int size():获取集合中的元素个数
* default void sort(Comparator<? super E> c)// 对集合进行特定排序

H:把集合转换成数组
  Object[] toArray():把集合变成数组。
  public <T> T[] toArray(T[] a) ;
2.2 ArrayList类

ArrayList是Java集合框架中使用最多的一个类,是一个数组队列,线程不安全集合。

它继承于AbstractList,实现了List, RandomAccess, Cloneable, Serializable接口。

  1. ArrayList实现List,得到了List集合框架基础功能;
  2. ArrayList实现RandomAccess,获得了快速随机访问存储元素的功能,RandomAccess是一个标记接口,没有任何方法;
  3. ArrayList实现Cloneable,得到了clone()方法,可以实现克隆功能;
  4. ArrayList实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。

2.2.1 ArrayList类结构特点:

  • 容量不固定,随着容量的增加而动态扩容(阈值基本不会达到)
  • 有序集合(插入的顺序==输出的顺序)
  • 插入的元素可以为null
  • 增删改查效率更高(相对于LinkedList来说)
  • 线程不安全

2.2.2 ArrayList类常用方法
ArrayList实现List集合框架基础功能,实现了所有方法的实现逻辑,无新增的公共方法,新增的私有方法也仅是助于处理逻辑。

  • 1.ArrayList全局变量
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{   
    private static final int DEFAULT_CAPACITY = 10; // 默认初始化容量为10

    private static final Object[] EMPTY_ELEMENTDATA = {}; // 创建一个空数组

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 创建一个拥有默认容量为10的空数组

    transient Object[] elementData; // ArrayList底层使用数组进行存储。设置为DEFAULTCAPACITY_EMPTY_ELEMENTDATA的list,在首次调用add方法时,容量会扩容为10.

    private int size; // ArrayList的大小,即元素的个数
    
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // list的最大容量
    }
  • 2.ArrayList构造器

ArrayList有三个构造器:

  1. 无参:创建空数组,调用方法时默认创建数组的容量为10
  2. 指定list长度:创建指定常数的数组
  3. 指定元素:创建容量大小为集合长度且元素确定的数组
     // 1. 创建空数组,调用方法时默认创建数组的容量为10
     public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
    // 2. 创建指定长度的list:底层创建指定长度的数组
     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);
        }
    }
    
     // 3. 创建一个包含指定元素的集合列表
     public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class); // 将集合转换成数组存储
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;// 创建空数组
        }
    }
  • 3 ArrayList添加元素及扩容
    ArrayList的add方法主要有两大类:
  1. 在list尾部添加元素或集合 :add(E e)、addAll(Collection<? extends E> c)
  2. 在list指定位置添加元素或集合:add(int index, E element)、addAll(int index, Collection<? extends E> c)

第2类方法中涉及到指定位置后元素的后移,源码中主要是调用System.arraycopy方法进行的元素后移和赋值操作;第1类的方法直接在尾部添加,不涉及元素的移动。

ArrayList调用add方法时首先会检查当前容量是否满足 size + 1(numNew)需求,如果满足则继续添加,如果不满足则进行扩容.

注意:ArrayList允许添加null,同时size+1;清空集合时元素置为null,size=0

 // 1.在list尾部添加元素
    public boolean add(E e) {
        ensureCapacityInternal(size + 1); // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
     //2.将集合c元素添加到在list尾部
     public boolean addAll(Collection<? extends E> c){
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew); // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    //3.在指定位置插入元素
     public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1); // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
    
 //4.在指定位置插入集合元素
     public boolean addAll(int index, Collection<? extends E> c){
        rangeCheckForAdd(index);
        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;
    }

ArrayList扩容的逻辑:

  1. 最小容量计算:minCapacity= size + 1(numNew)
  • 如果list为DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则所需最小容量为:Math.max(DEFAULT_CAPACITY, minCapacity)
  • 否则,所需最小容量为:minCapacity
  1. 当前容量与最小容量(minCapacity)判断:
  • 如果当前容量>最小容量(minCapacity),则进行正常添加
  • 如果当前容量<最小容量(minCapacity),则进行扩容
  1. 扩容:
  • 将当前容量扩充为原来的1.5倍,得到新容量
  • 如果新容量>最小容量(minCapacity),则新容量成立;如果新容量<最小容量(minCapacity),则新容量=最小容量(minCapacity)
  1. 新容量阈值判断:MAX_ARRAY_SIZE
  • 如果新容量<MAX_ARRAY_SIZE,则新容量成立
  • 如果新容量超过MAX_ARRAY_SIZE
    • 若最小容量(minCapacity) <MAX_ARRAY_SIZE,则新容量=MAX_ARRAY_SIZE
    • 若最小容量(minCapacity) >MAX_ARRAY_SIZE,则新容量=Integer.MAX_VALUE

注意:list扩容是将当前元素复制到新数组,返回新数组elementData = Arrays.copyOf(elementData, newCapacity)

// 与扩容相关的方法
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    
     private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
     private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
    
     private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
  • 4.ArrayList交集、差集
    removeAll和retainAll方法都涉及到元素的删除,底层均调用了batchRemove方法,只不过传递的参数不同
    batchRemove方法的处理逻辑:
    1. 将符合条件的元素重新放置在数组中(从下标0开始)
    2. 全部筛选完后,将剩余位置的元素设为null
  // 删除两个集合的交集
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
    // 保留两个集合的交集
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }
    
    // 集合操作过程
    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }
  • 5.ArrayList元素移动
    因为ArrayList是用连续的地址存储元素,所以当list在指定位置添加或删除元素(或集合)时,需要将指定位置后的所有元素向后或向前移动一位(或N位)。

ArrayList对应的方法有:

  1. add(int index, E element)、addAll(int index, Collection<? extends E> c)
  2. remove(int index)、removeRange(int fromIndex, int toIndex)、 remove(Object o)

此类方法底层均为调用 System.arraycopy方法实现元素的移动。

    // 1.在指定位置添加元素
     public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1); // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        size++;
    }
   // 2.在指定元素添加集合元素
   public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        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;
    }
   // 3.删除指定位置的元素
    public E remove(int index);
     {
        rangeCheck(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;
    }
    
      // 4.删除指定范围内的元素
     protected void removeRange(int fromIndex, int toIndex){
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }
    
    // 5.删除指定元素
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
   
   // 快速删除指定位置元素
   private void fastRemove(int index) {
        modCount++;
        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
    } 
  • 6.ArrayList迭代器
    ArrayList内置了两个迭代器:Itr、ListItr:
  1. Itr实现Iterator接口,主要针对集合操作,定义了hasNext、next、remove等方法的实现逻辑
  2. ListItr继承Itr类、实现了ListIterator接口,主要针对list 集合进行操作,定义了 nextIndex、previous、previousIndex、set、add等方法的实现逻辑

ArrayList内置迭代器方法的实现逻辑与AbstractList内置迭代器的方法逻辑相同。

ArrayList主要有三种方法调用迭代器:iterator()、listIterator()、listIterator(int index)

注意:在调用迭代器时,不能对原list进行修改操作;同时对set、add、remove方法只能操作一次。迭代器具体实现逻辑可见【集合迭代器】详解

   // 1.调用Itr迭代器
   public Iterator<E> iterator() {
        return new Itr();
    }
   // 2.调用listIterator迭代器    
   public ListIterator<E> listIterator() {
        return new ListItr(0);
    }
    // 3.指定位置开始调用listIterator迭代器       
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

  • 7.ArrayList常用一般方法
  1. ArrayList中注意区分元素个数(size)与数组容量
  2. trimToSize( )方法去除多余的容量,将元素位置与个数相等的新数组赋值给当前数组。
  3. clone()方法返回元素位置与个数相等的新集合
  4. clear()将元素全部置为null,size=0
  5. isEmpty()判断size==0
   public boolean isEmpty() {
        return size == 0;
    }
    
*   E elementData(int index) {
        return (E) elementData[index];
    } 
    
    public int indexOf(Object o);// 返回元素在集合中第一次出现的位置,元素O可以为null,查找不到返回-1 
    // 去掉预留元素位置:使数组容量=数组元素个数(size)
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }
     //克隆当前集合为新的集合对象
*   public Object clone(){ 
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
     
    public void clear() {
        modCount++;
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
    }

#####3. Queue
######3.1.Queue接口

Queue接口继承Collection接口,在Collection接口基本操作的基础上,新增了添加、获取、删除方法,每种方法都有两种方式:1.如果操作失败抛出异常;2.如果操作失败返回null或false。


public interface Queue<E> extends Collection<E> {

 #添加元素

    boolean add(E e);// 添加成功返回true;如果因为容量有限添加失败,则抛出异常IllegalStateException

    

    boolean offer(E e);// 添加成功返回true,否则返回false。

    

    #删除头元素

    E remove();// 删除头元素,如果队列为空,抛出异常NoSuchElementException

    

    E poll();// 获取头元素,如果队列为空返回null

    

    #查询头元素,并不删除头元素

    E element();// 查询头元素,如果队列为空抛出异常NoSuchElementException

    

    E peek();// 查询头元素,如果队列为空返回null 

}

3.2.Deque接口

Deque接口中的方法可以分为:

  • 针对双端队列:1.在队列的first、last进行add、remove、get的6大类方法;2.删除特定元素:removeFirstOccurrence(Object o)、removeLastOccurrence(Object o)。
  • 针对队列:add、remove、get的3大类方法。
  • 针对栈:push、pop的2个方法
  • 针对集合:1.特定元素的获取或删除:contains(Object o)、remove(Object o);2.元素个数: size();3.迭代器:iterator()、descendingIterator()

Deque接口特点:
Deque接口继承Queue接口,所以涉及到add、remove、get操作提供了两种方式:1.操作失败抛异常;2.操作失败返回null或false。
Deque接口不支持下标访问元素。

public interface Deque<E> extends Queue<E> {
   /** 双端队列的方法
   */
#添加元素至队列头部
   void addFirst(E e);// 添加成功返回true,若因容量受限添加失败,抛出异常:IllegalStateException
   
   boolean offerFirst(E e); // 添加成功返回true,否则返回false
   #添加元素至队列尾部
   void addLast(E e);// 添加成功返回true,若因容量受限添加失败,抛出异常:IllegalStateException
   
   boolean offerLast(E e);// 添加成功返回true,否则返回false
   
   #删除队列头元素
   E removeFirst();// 删除头元素,如果队列为空,抛出异常:NoSuchElementException
   
   E pollFirst();// 删除头元素,如果队列为空返回null

   #删除队列尾元素
   E removeLast();// 删除尾元素,如果队列为空,抛出异常:NoSuchElementException
   
   E pollLast();// 删除尾元素,如果队列为空返回null
   
   #获取队列头元素
   E getFirst();// 获取头元素,如果队列为空,抛出异常:NoSuchElementException
   
   E peekFirst();// 获取头元素,如果队列为空返回null

   #获取队列尾元素
   E getLast();// 获取尾元素,如果队列为空,抛出异常:NoSuchElementException

   E peekLast();// 获取尾元素,如果队列为空返回null
   
   #将队列首次出现的元素o删除
   boolean removeFirstOccurrence(Object o);// 如果删除成功返回true
   
   #将队列最后出现的元素o删除
   boolean removeLastOccurrence(Object o);// 如果删除成功返回true

   /** Queue接口方法
   */
#在队列尾部添加元素
   boolean add(E e);// 添加成功返回true;如果因为容量有限添加失败,则抛出异常IllegalStateException
   
   boolean offer(E e);// 添加成功返回true,否则返回false。
   
   #删除队列尾部元素
   E remove();// 如果队列为空,抛出异常NoSuchElementException
   
   E poll();// 如果队列为空返回null
   
   #查询队列头元素,并不删除头元素
   E element();// 如果队列为空抛出异常NoSuchElementException
   
   E peek();// 如果队列为空返回null  
   
   /** 栈Stack方法,只在栈顶进行元素的入栈和出栈
   */
   #元素入栈
   void push(E e);// 入栈成功返回true,如果因为容量受限,抛出异常:IllegalStateException

#元素出栈
   E pop();// 如果队列为空,抛出异常:NoSuchElementException
   
   /** 集合Collection方法
   */
   # 删除队列首次出现的元素o
   boolean remove(Object o);// 删除成功返回true。 方法等同于 removeFirstOccurrence(Object o) 方法
   
   # 判断队列中是否包含元素o
   boolean contains(Object o);// 如果包含返回true,否则返回false
   
   # 队列元素个数
   public int size();

#队列迭代器
   Iterator<E> iterator(); 
   
   #队列反转的迭代器
   Iterator<E> descendingIterator();

}
3.3.LinkedList

LinkedList是一个双向链表,每一个节点都拥有指向前后节点的引用。相比于ArrayList来说,LinkedList的随机访问效率更低。

它继承AbstractSequentialList,实现了List, Deque, Cloneable, Serializable接口。
(1)LinkedList实现List,得到了List集合框架基础功能;
(2)LinkedList实现Deque,Deque 是一个双向队列,也就是既可以先入先出,又可以先入后出,说简单些就是既可以在头部添加元素,也可以在尾部添加元素;
(3)LinkedList实现Cloneable,得到了clone()方法,可以实现克隆功能;
(4)LinkedList实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。

2.常用方法


3.源码分析

       LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为null
       list.add(123);//将123封装到Node中,创建了Node对象。
       其中,Node定义为:体现了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;
            }
        }

######3.4. ArrayList和LinkedList比较
LinkedList和ArrayList之前的区别主要就是数组和链表的区别。
数组中查询和赋值比较快,因为可以直接通过数组下标访问指定位置。

链表中删除和增加比较快,因为可以直接通过修改链表的指针(Java中并无指针,这里可以简单理解为指针。其实是通过Node节点中的变量指定)进行元素的增删。

所以,LinkedList和ArrayList相比,增删的速度较快。但是查询和修改值的速度较慢。同时,LinkedList还实现了Queue接口,所以他还提供了offer(), peek(), poll()等方法。
https://www.jianshu.com/p/63b01b6379fb

#####4. Vector
Vector和ArrayList一样,都是通过数组实现的,但是Vector是线程安全的。和ArrayList相比,其中的很多方法都通过同步(synchronized)处理来保证线程安全。

如果你的程序不涉及到线程安全问题,那么使用ArrayList是更好的选择(因为Vector使用synchronized,必然会影响效率)。

二者之间还有一个区别,就是扩容策略不一样。在List被第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当List认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。

#####5. 如何选择
如果涉及到多线程,那么就选择Vector(当然,你也可以使用ArrayList并自己实现同步)。

如果不涉及到多线程就从LinkedList、ArrayList中选。 LinkedList更适合从中间插入或者删除(链表的特性)。 ArrayList更适合检索和在末尾插入或删除(数组的特性)。

链接:https://www.jianshu.com/p/1149f1bf1736

发布了18 篇原创文章 · 获赞 0 · 访问量 713

猜你喜欢

转载自blog.csdn.net/qq_39953750/article/details/104758632
今日推荐