ArrayList, LinkedList, Vector - dudu:史上最详解
ArrayList, LinkedList, Vector - dudu:史上最详解
我们来比较一下ArrayList, LinkedLIst和Vector它们之间的区别。BZ的JDK版本是1.7.0_80
经常在面试的时候,或者在大家做project的时候,都会被它们的区别产生疑惑。或者对它们的用法并不是很了解。那么我们今天就来看看他们的区别和用法。
以下是本文的大纲:
一.ArrayList,LinkedList和Vector的区别
若有不正之处,还请多多谅解,并希望批评指正。
请尊重作者劳动成果,转发请标明blog地址
https://www.cnblogs.com/hongten/p/hongten_arraylist_linkedlist_vector.html
一.ArrayList,LinkedList和Vector的区别
ArrayList, LinkedList和Vector都实现了List接口,所使用的方法也很相似,主要区别在于实现方法的不同,所有对不同的操作具有不同的效率。
1.ArrayList
ArrayList是一个可以改变大小的,线程不同步(不支持并发)的数组,内部值可以为null。 当更多的元素加入到ArrayList中时,其大小会自动增加,内部元素可以直接通过get/set方法进行访问,因为ArrayList本质上即使一个数组。
因为ArrayList是不支持并发的数组,但是如果我们在使用的过程中需要ArrayList也有同步功能,可以使用Collections.synchronziedList(new ArrayList<E e>())方法实现(在后面我们会讲到)。
2.Vector
之所以把Vector放在这里的原因是因为Vector和ArrayList是否类似,但是它是属于线程同步(支持并发)的数组,并且内部值也可以为null。如果你的程序本身是线程安全的(没有多个线程之间共享同一个集合/对象),那么请使用ArrayList吧。
3.LinkedList
LinkedList底层是基于双链表实现的,在添加和删除元素时具有比ArrayList更好的性能。但是在get/set方面要弱于ArrayList(前提是这些对比是在数据量很大或者操作很繁琐的情况下)。LinkedList内部值可以为null,但是当我们调用值为null的元素的时候会出现NullPointerException。
LinkedList更适合于以下场景:
I.没有大量的随机访问操作。
II.有大量的add/remove操作。
概括起来大概是这个样子:
ArrayList和Vector它们底层实现为数组,值可为null, ArrayList不支持并发,Vector支持并发;
LinkedList底层基于双链表,因此在add/remove元素时比ArrayList要快(注意前提)。
二.详解ArrayList
先来看看ArrayList的源码
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { transient int size = 0; //第一个元素的引用 transient Node<E> first; //最后一个元素的引用 transient Node<E> last; //无参构造函数 public LinkedList() { } //包含一个Collection的构造函数 public LinkedList(Collection<? extends E> c) { this(); addAll(c); } //在链表头部创建链接 private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; } //在链表尾部创建链接 void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; } /** * Inserts element e before non-null Node succ. */ void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; } //删除链表中第一个链接 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--; modCount++; return element; } //删除链表中最后一个链接 private E unlinkLast(Node<E> l) { // assert l == last && l != null; final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; } //删除链表给定的元素链接 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 getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } //获取尾部元素 public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } //移除头部元素 public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); } //移除尾部元素 public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); } //添加一个元素在链表头部 public void addFirst(E e) { linkFirst(e); } //添加一个元素到链表尾部 public void addLast(E e) { linkLast(e); } //判断是否包含某个元素 public boolean contains(Object o) { return indexOf(o) != -1; } //获取链表大小 public int size() { return size; } //添加元素 public boolean add(E e) { //把该元素放到链表最后面 linkLast(e); return true; } //移除链表中一个给定的元素对象 public boolean remove(Object o) { if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == 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; } //添加一个包含Collection的元素 public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } //在给定的索引下面添加一个包含Collection的元素 public boolean addAll(int index, Collection<? extends E> c) { checkPositionIndex(index); Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; Node<E> pred, succ; if (index == size) { succ = null; pred = last; } else { succ = node(index); pred = succ.prev; } for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); if (pred == null) first = newNode; else pred.next = newNode; pred = newNode; } if (succ == null) { last = pred; } else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true; } //清除链表 public void clear() { for (Node<E> x = first; x != null;) { Node<E> next = x.next; x.item = null; x.next = null; x.prev = null; x = next; } first = last = null; size = 0; modCount++; } // Positional Access Operations //根据索引获取元素 public E get(int index) { checkElementIndex(index); return node(index).item; } //根据索引设置索引所指向的对象的值 public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; } //根据索引添加元素 public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); } //根据索引移除元素 public E remove(int index) { checkElementIndex(index); return unlink(node(index)); } //判断所给索引是否合法 private boolean isElementIndex(int index) { return index >= 0 && index < size; } //判断所给索引是否为第一个/最后一个 private boolean isPositionIndex(int index) { return index >= 0 && index <= size; } private void checkElementIndex(int index) { if (!isElementIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private void checkPositionIndex(int index) { if (!isPositionIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } Node<E> node(int index) { 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; } } public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); } //Queue里面offer()方法 public boolean offer(E e) { return add(e); } //Deque里面offerFirst()方法 public boolean offerFirst(E e) { addFirst(e); return true; } //Deque里面offerLast()方法 public boolean offerLast(E e) { addLast(e); return true; } public ListIterator<E> listIterator(int index) { checkPositionIndex(index); return new ListItr(index); } 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源码,中文注解
我们可以看到LinkedList继承了AbstractSequentialList,并且实现了List, Deque, Cloneable, Serializable接口,LinkedList底层是基于链表实现的。
所以我们必须去了解一下链表的数据结构。
在LinkedList里面定义了一个私有静态内部类Node,可以看到Node有三个成员变量,item, next, prev.从字面上理解为本身, 下一个元素,前一个元素。
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; } }
add()方法
来看看add()方法,该方法是直接把元素放到链表尾部,然后返回。
//添加元素 public boolean add(E e) { //把该元素放到链表最后面 linkLast(e); return true; }
linkLast()方法
把对象加入到链表的尾部,然后链表大小+1
// 第一个元素的引用 transient Node<E> first; // 最后一个元素的引用 transient Node<E> last; //在链表尾部创建链接 void linkLast(E e) { //获取最后一个元素 final Node<E> l = last; //创建一个一个Node对象,参数(前,本,后) //前:指向链表最后一个元素,即新加入的元素的上一个元素 //本:指的就是新加入元素本身 //后:因为新加入的元素本身就是在链表最后面加入,所以,后面没有元素,则为null final Node<E> newNode = new Node<>(l, e, null); //把last引用指向新创建的对象上面 last = newNode; //如果在链表为空的情况下,first=last=null if (l == null) //那么第一个就是最新创建的元素 first = newNode; else //把链表最后元素的next指向创建的新元素的引用 l.next = newNode; //链表大小+1 size++; modCount++; }
remove()方法
根据索引移除对象,首先要判断索引是否合法,如果合法,则移除索引所指对象。
//根据索引移除元素 public E remove(int index) { checkElementIndex(index); return unlink(node(index)); }
unlink()方法
unlink()方法的目的就是把即将被删除的元素从链表里面拿出来,并且维护好链表状态。
//删除链表给定的元素链接 E unlink(Node<E> x) { //该元素本身 final E element = x.item; //该元素下一个元素 final Node<E> next = x.next; //该元素上一个元素 final Node<E> prev = x.prev; //如果该元素本身就是第一个元素,即链表头部 if (prev == null) { //那么就把first指向下一个元素引用 first = next; } else { //把前一个元素的next指向该元素的下一个元素,即跳过该元素 //因为该元素马上要被删除掉了 prev.next = next; //把该元素前一个元素引用置空 x.prev = null; } //如果该元素本身就是最后一个元素,即链表尾部 if (next == null) { //那么把last指向前一个元素引用 last = prev; } else { //把下一个元素的prev指向该元素的上一个元素,也是跳过该元素(即将被删) next.prev = prev; //把该元素下一个元素引用置空 x.next = null; } //把该元素本身置空 x.item = null; //链表大小-1 size--; modCount++; //返回该元素 return element; }
五.在并发情况下,怎样使用它们
类部类MyThread继承了Thread类,并且重写了run()方法。在MyThread里面定义了4个static变量,这些变量是为了存放线程在运行过程中向里面添加元素的值。
package com.b510.test; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Vector; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * @author Hongwei * @created 28 Aug 2018 */ public class MyListTest { public static void main(String[] args) throws Exception { // 创建线程池 ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new MyThread()); exec.execute(new MyThread()); exec.execute(new MyThread()); exec.execute(new MyThread()); exec.execute(new MyThread()); exec.execute(new MyThread()); exec.execute(new MyThread()); exec.execute(new MyThread()); exec.execute(new MyThread()); System.out.println("begin..."); TimeUnit.SECONDS.sleep(2); exec.shutdownNow(); List<Integer> myArrayList = MyThread.myArrayList; List<Integer> myLinkedList = MyThread.myLinkedList; List<Integer> myVector = MyThread.myVector; List<Integer> mySynchronziedArrayList = MyThread.mySynchronziedArrayList; if (myArrayList != null && myArrayList.size() > 0) { System.out.println("ArrayList: " + myArrayList); } if (myVector != null && myVector.size() > 0) { System.out.println("vector: " + myVector); } if (mySynchronziedArrayList != null && mySynchronziedArrayList.size() > 0) { System.out.println("SynchronziedArrayList: " + mySynchronziedArrayList); } if (myLinkedList != null && myLinkedList.size() > 0) { System.out.println("linkedList: " + myLinkedList); } System.out.println("end..."); } } class MyThread extends Thread { //arrayList,不支持并发 static List<Integer> myArrayList = new ArrayList<Integer>(); //linkedList static List<Integer> myLinkedList = new LinkedList<Integer>(); //Vector,线程安全,支持并发 static List<Integer> myVector = new Vector<Integer>(); //Connections.synchonizedList,线程安全,支持并发 static List<Integer> mySynchronziedArrayList = Collections.synchronizedList(new ArrayList<Integer>()); public void run() { for (int i = 0; i < 10; i++) { try { TimeUnit.MILLISECONDS.sleep(2); System.out.println(Thread.currentThread().getName() + " add value " + i); myArrayList.add(i); myVector.add(i); mySynchronziedArrayList.add(i); myLinkedList.add(i); } catch (InterruptedException e) { e.printStackTrace(); } } } } /* output: begin... pool-1-thread-1 add value 0 pool-1-thread-3 add value 0 pool-1-thread-8 add value 0 pool-1-thread-4 add value 0 pool-1-thread-7 add value 0 pool-1-thread-6 add value 0 pool-1-thread-2 add value 0 pool-1-thread-5 add value 0 pool-1-thread-9 add value 0 pool-1-thread-5 add value 1 pool-1-thread-4 add value 1 pool-1-thread-6 add value 1 pool-1-thread-8 add value 1 pool-1-thread-2 add value 1 pool-1-thread-3 add value 1 pool-1-thread-7 add value 1 pool-1-thread-1 add value 1 pool-1-thread-9 add value 1 pool-1-thread-7 add value 2 pool-1-thread-3 add value 2 pool-1-thread-5 add value 2 pool-1-thread-2 add value 2 pool-1-thread-8 add value 2 pool-1-thread-6 add value 2 pool-1-thread-4 add value 2 pool-1-thread-1 add value 2 pool-1-thread-9 add value 2 pool-1-thread-8 add value 3 pool-1-thread-1 add value 3 pool-1-thread-2 add value 3 pool-1-thread-3 add value 3 pool-1-thread-7 add value 3 pool-1-thread-5 add value 3 pool-1-thread-4 add value 3 pool-1-thread-6 add value 3 pool-1-thread-9 add value 3 pool-1-thread-3 add value 4 pool-1-thread-7 add value 4 pool-1-thread-4 add value 4 pool-1-thread-8 add value 4 pool-1-thread-2 add value 4 pool-1-thread-6 add value 4 pool-1-thread-1 add value 4 pool-1-thread-5 add value 4 pool-1-thread-9 add value 4 pool-1-thread-1 add value 5 pool-1-thread-6 add value 5 pool-1-thread-2 add value 5 pool-1-thread-3 add value 5 pool-1-thread-7 add value 5 pool-1-thread-5 add value 5 pool-1-thread-8 add value 5 pool-1-thread-4 add value 5 pool-1-thread-9 add value 5 pool-1-thread-8 add value 6 pool-1-thread-5 add value 6 pool-1-thread-6 add value 6 pool-1-thread-1 add value 6 pool-1-thread-2 add value 6 pool-1-thread-3 add value 6 pool-1-thread-7 add value 6 pool-1-thread-4 add value 6 pool-1-thread-9 add value 6 pool-1-thread-8 add value 7 pool-1-thread-3 add value 7 pool-1-thread-1 add value 7 pool-1-thread-6 add value 7 pool-1-thread-7 add value 7 pool-1-thread-2 add value 7 pool-1-thread-4 add value 7 pool-1-thread-5 add value 7 pool-1-thread-9 add value 7 pool-1-thread-1 add value 8 pool-1-thread-6 add value 8 pool-1-thread-3 add value 8 pool-1-thread-7 add value 8 pool-1-thread-2 add value 8 pool-1-thread-5 add value 8 pool-1-thread-8 add value 8 pool-1-thread-4 add value 8 pool-1-thread-9 add value 8 pool-1-thread-1 add value 9 pool-1-thread-4 add value 9 pool-1-thread-7 add value 9 pool-1-thread-3 add value 9 pool-1-thread-2 add value 9 pool-1-thread-8 add value 9 pool-1-thread-6 add value 9 pool-1-thread-5 add value 9 pool-1-thread-9 add value 9 ArrayList: [null, null, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9] vector: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9] SynchronziedArrayList: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9] Exception in thread "main" java.lang.NullPointerException at java.util.LinkedList$ListItr.next(LinkedList.java:891) at java.util.AbstractCollection.toString(AbstractCollection.java:457) at java.lang.String.valueOf(String.java:2849) at java.lang.StringBuilder.append(StringBuilder.java:128) at com.b510.test.MyListTest.main(MyListTest.java:49) */
之后我们从结果可以看到:
ArrayList:值可以为null,线程不安全,但是我们可以使用Collections.synchronzedList()方法使得一个ArrayList支持并发。
Vector:本身支持并发。
LinkedList:值可以为null,但是当我们调用时会抛出NullPointerException异常。
========================================================
More reading,and english is important.
I'm Hongten
大哥哥大姐姐,觉得有用打赏点哦!你的支持是我最大的动力。谢谢。
Hongten博客排名在100名以内。粉丝过千。
Hongten出品,必是精品。
E | hongtenzone@foxmail.com B | http://www.cnblogs.com/hongten
========================================================
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=14s169zyimbmg
- Java 集合之List、ArrayList、LinkedList以及Vector详解
- 100_容器_List_ArrayList_LinkedList_Vector用法_详解
- LinkedList、ArrayList、 Vector的区别和详解
- Java中 ArrayList、Vector和LinkedList 的使用和详解(转)
- List-ArrayList 与LinkedList、Vector以及迭代器详解
- Java集合类ArrayList、LinkedList、vector、SynchronizedList详解
- 容器第二课,List,ArrayList,LinkedList,Vector用法详解
- java集合(ArrayList,Vector,LinkedList,HashSet,TreeSet的功能详解)
- 详解Java中ArrayList、Vector、LinkedList三者的异同点
- 详解Java中ArrayList、Vector、LinkedList三者的异同点
- java集合(ArrayList,Vector,LinkedList,HashSet,TreeSet的功能详解)
- Java中 ArrayList、Vector和LinkedList 的使用和详解!
- 集合Collection中ArrayList、LinkedList、Vector的用法详解
- Java ArrayList、Vector和LinkedList等的差别与用法(转)
- ArrayList和LinkedList和Vector
- ArrayList vs. LinkedList vs. Vector
- arraylist linkedlist vector
- JAVA之旅(十九)——ListIterator列表迭代器,List的三个子类对象,Vector的枚举,LinkedList,ArrayList和LinkedList的小练习
- 具体的集合类(一)ArrayList,LinkedList,Vector,HashMap,HashTable
- Java ArrayList、Vector和LinkedList等的差别与用法(转)