一、List 实现类之 UML 类图
截取自本人博文: Java 集合框架 (The Collections Framework) 之 UML 类图
附:CopyOnWriteArrayList (List接口的直接子实现类)
二、ArrayList
2.1 ArrayList 的类声明
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//
}
根据 ArrayList 的类声明可以知道,ArrayList 支持随机访问、支持克隆、支持序列化
2.2 ArrayList 的成员变量
可见,ArrayList 的底层实现是Object数组。
在类声明可以知道,ArrayList 支持序列化,但是从成员变量声明可知,ArrayList 的底层存储 elementData 不支持序列化,因为存在 transient 关键字?关于 transient 关键字说明如下:
- 被transient关键字修饰过得类成员变量能被序列化,但是类需要实现 Exteranlizable 接口、重写
writeExternal(ObjectOutput out)
和readExternal(ObjectInput in)
并自己指定是否序列化哪些属性- out.writeObject(elementData);
- elementData = (Object[]) in.readObject();
- 静态变量即使没有transient关键字修饰也不会被序列化;
关于 transient 关键字详细内容可见:java中的关键字transient,这篇文章你再也不发愁了
2.3 ArrayList 构造方法
- 空构造方法
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
ArrayList 的 空构造方法构建一个初始容量为10的空列表。但是,通过private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
可以发现,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 其实为空数组,那么如何理解呢?首先,我们查看一下ArrayList的Add方法:
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
假设我们使用空构造方法构造了一个ArrayList,当我们使用add(E e)方法添加第一个元素时,显然会调用ensureCapacityInternal(int minCapacity)
,如下所示
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
由于size是int型的成员变量,使用空构造方法构造ArrayList时默认为0,那么此时minCapacity为1。然后我们继续查看
calculateCapacity(Object[] elementData, int minCapacity)
的代码:
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
由于使用空构造方法构造ArrayList时,elementData已经赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA,故方法返回DEFAULT_CAPACITY的值10。
继而看向ensureExplicitCapacity(int minCapacity)
方法:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
由于minCapacity为10,而elementData.length此时为0,故而转向private void grow(int minCapacity)
方法:
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
显然,执行到elementData = Arrays.copyOf(elementData, newCapacity)
时,newCapacity为10,故而得到的elementData的初始大小为10,然后即执行elementData[size++] = e
对第一个元素(index=0,即elementData[0]=e)赋值,size变为1。
- 带参构造方法
public ArrayList(int initialCapacity){}
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
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);
}
}
该构造方法构造一个初始容量为initialCapacity
的ArrayList,我们考虑一下initialCapacity
为0时(elementData
赋值为EMPTY_ELEMENTDATA
,确实初始容量为0),第一个元素的插入情况。首先还是执行add(E e)
方法,然后是ensureCapacityInternal(int minCapacity)
(minCapacity
为0),接着是calculateCapacity(Object[] elementData, int minCapacity)
,由于elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA
,故而返回值为1,继而执行ensureExplicitCapacity(int minCapacity)
与grow(int minCapacity)
,使得elementData的容量为1,然后执行elementData[size++] = e
,完成插入操作,size变为1。
- 带参构造方法
public ArrayList(Collection<? extends E> c){}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
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;
}
}
上述代码中,比较难以理解的是:
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
针对于此,我们编写一段代码来说明其作用:
import java.util.*;
/**
* @author 32098
*/
public class Test {
public static void main(String[] args) {
System.out.println("########################");
Object[] strs = new String[]{"a", "b", "c"};
System.out.println(strs.getClass());
// strs[0] = new Object(); 之所以注释掉是因为会出现运行时异常,故采用try的原因使后面代码正常运行
try {
strs[0] = new Object();
}catch (Exception e) {
// java.lang.ArrayStoreException: java.lang.Object ? 为什么Object[]不能存储Object实例?
e.printStackTrace();
}
if(strs.getClass() != Object[].class){
strs = Arrays.copyOf(strs, strs.length, Object[].class);
}
System.out.println(strs.getClass() + " " + Object[].class);
// 经过strs = Arrays.copyOf(strs, strs.length, Object[].class),Object[]能存储Object实例
strs[1] = new Object();
// 使用构造方法构造ArrayList
System.out.println("########################");
List<Object> list = new ArrayList<>(Arrays.asList("a", "b"));
Object[] elementData = Arrays.asList("a", "b").toArray();
System.out.println(list.getClass());
System.out.println(elementData.getClass());
list.set(0, new Object());
// java.lang.ArrayStoreException: java.lang.Object
elementData[0] = new Object();
}
}
以下是运行结果:
因此,那部分的代码是为了使 elementData 的 class 由class [Ljava.lang.String;
改为class [Ljava.lang.Object;
,使elementData的class符合于Object[].class
,使与声明transient Object[] elementData;
一致,从而能够使类似list.set(0, new Object());
的语句不出现 ArrayStoreException
。
2.4 ArrayList 的线程安全性
通过查看源码,ArrayList 的方法均没有synchronized
关键字且方法体无任何锁机制,故而是线程不安全的。
三、Vector
3.1 Vector 的类声明
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
}
根据 Vector 的 类声明可知,Vector 支持随机访问、支持克隆、支持序列化
3.2 Vector 的成员变量
- 根据成员变量可知,Vector 的底层实现是Object数组:elementData;
- elementCount:Vector 包含的元素数量;
- capacityIncrement:向量容量的增加数,如果为0或小于0,向量容量加倍,否则向量容量加+capacityIncrement,见如下代码
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
3.3 Vector 的构造方法
-
构造方法集A:
上图三个构造方法比较简单,容易看懂理解 -
构造方法集B:
仅 if 语句块比较难以理解,但是该内容已经在 ArrayList 的构造方法中已提及,如果认真阅读了上文 ArrayList 的构造方法部分,那么就不存在任何问题。
3.4 Vector 的线程安全性
通过查看 Vector 源码,Vector 是线程安全的,因为 Vector 的方法直接或间接的都包含synchronized关键字;
四、Stack
4.1 Stack 的底层实现
根据源码,Stack 的底层实现是依赖于 Vector 的方法来实现 LIFO(Last In, First Out) 的。
4.2 Stack 的线程安全性
通过查看 Stack 源码,Stack 是线程安全的,因为其方法直接或间接的包含synchronized关键字;
五、LinkedList
5.1 LinkedList 类声明
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//
}
根据 Vector 的 类声明可知,Vector 不支持随机访问,支持克隆、支持序列化
5.2 LinkedList 成员变量
- 根据上图可得:
- LinkedList 的成员变量包括一个int型的size、两个Node(分别为第一个节点与最后一个节点),不能被序列化
- LinkedList 是双向链表
- Node 是什么?
查看 LinkedList 的源码可知,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;
}
}
因此,LinkedList 的底层实现是 Node 内部类。
5.3 LinkedList 构造方法
- 空构造方法
/**
* Constructs an empty list.
*/
public LinkedList() {
}
构建一个空链表。
- 带参构造方法:从集合构造链表
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
addAll()方法
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
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;
}
根据成员变量注释,不难理解该构造方法构造链表的过程:
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
5.4 LinkedList 的线程安全性
通过查看 LinkedList 的源码,LinkedList 是线程不安全的,因为它的所有方法均不存在synchronized关键字且方法体无任何锁机制。
六、CopyOnWriteArrayList
6.1 CopyOnWriteArrayList 的类声明
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//
}
根据 CopyOnWriteArrayList 的 类声明可知,CopyOnWriteArrayList 支持随机访问、支持克隆、支持序列化。
6.2 CopyOnWriteArrayList 的成员变量
/** The lock protecting all mutators */
final transient ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
第一个成员变量lock,类型为 ReentrantLock ,显然是用于保证 CopyOnWriteArrayList 的线程安全性的;第二个成员变量array,即 CopyOnWriteArrayList 的底层存储,因此 CopyOnWriteArrayList 的底层是基于 Object 数组的。
6.3 CopyOnWriteArrayList 的构造方法
6.4 CopyOnWriteArrayList 的线程安全性
CopyOnWriteArrayList 是线程安全的,原因是:CopyOnWriteArrayList 的写方法体要么使用了独占锁lock,要么使用了写时复制(修改对象时,复制一份,并在复制的对象中修改并在修改后更改引用为新复制的对象,这可能出现的问题是:数据一致性问题,因为在修改后更改引用前,其他线程读到的数据仍然是修改前的数据)
- 使用独占锁的情况
/**
* Replaces the element at the specified position in this list with the
* specified element.
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
- 写时复制的情况
/**
* Removes the first occurrence of the specified element from this list,
* if it is present. If this list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
* {@code i} such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
* (if such an element exists). Returns {@code true} if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
*
* @param o element to be removed from this list, if present
* @return {@code true} if this list contained the specified element
*/
public boolean remove(Object o) {
Object[] snapshot = getArray();
int index = indexOf(o, snapshot, 0, snapshot.length);
return (index < 0) ? false : remove(o, snapshot, index);
}
/**
* A version of remove(Object) using the strong hint that given
* recent snapshot contains o at the given index.
*/
private boolean remove(Object o, Object[] snapshot, int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] current = getArray();
int len = current.length;
if (snapshot != current) findIndex: {
int prefix = Math.min(index, len);
for (int i = 0; i < prefix; i++) {
if (current[i] != snapshot[i] && eq(o, current[i])) {
index = i;
break findIndex;
}
}
if (index >= len)
return false;
if (current[index] == o)
break findIndex;
index = indexOf(o, current, index, len);
if (index < 0)
return false;
}
Object[] newElements = new Object[len - 1];
System.arraycopy(current, 0, newElements, 0, index);
System.arraycopy(current, index + 1,
newElements, index,
len - index - 1);
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
附:关于写时复制,可查看:CopyOnWriteArrayList
七、总结
7.1 List 实现类的线程安全性
- ArrayList 是线程不安全的
- Vector 是线程安全的
- Stack 是线程安全的
- LinkedList 线程不安全的
- CopyOnWriteArrayList 是线程安全的
7.2 List 实现类的底层实现
- ArrayList 的底层实现是 Object 数组
- Vector 的底层实现是 Object 数组
- Stack 的底层实现是 Object 数组 (Stack 底层是基于 Vector 的,故其底层实现基于 Object 数组)
- LinkedList 的底层实现是 Node 内部类
- CopyOnWriteArrayList 的底层实现是 Object 数组
7.3 List 实现类的随机访问性
- ArrayList 支持随机访问
- Vector 支持随机访问
- Stack 不支持随机访问
- LinkedList 不支持随机访问
- CopyOnWriteArrayList 支持随机访问