您的位置:首页 > 其它

ArrayList, LinkedList, Vector - dudu:史上最详解

2018-08-29 15:51 477 查看

ArrayList, LinkedList, Vector - dudu:史上最详解

我们来比较一下ArrayList, LinkedLIst和Vector它们之间的区别。BZ的JDK版本是1.7.0_80

经常在面试的时候,或者在大家做project的时候,都会被它们的区别产生疑惑。或者对它们的用法并不是很了解。那么我们今天就来看看他们的区别和用法。

以下是本文的大纲:

一.ArrayList,LinkedList和Vector的区别

二.详解ArrayList

三.详解Vector

四.详解LinkedList

五.在并发情况下,怎样使用它们

若有不正之处,还请多多谅解,并希望批评指正。

请尊重作者劳动成果,转发请标明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

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: