2.集合-Collection接口
集合介绍
Collection接口介绍
Map接口介绍
List接口
ArrayList源码分析
ArrayList初始化
/**
* Default initial capacity.
*/
//默认初始容量
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
//默认容量的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
//list中的数据
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
//list的大小
private int size;
无参构造
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
//将空数组赋值到存储数据的数组中
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造
/**
* 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) {
//如果传的参数大于0
if (initialCapacity > 0) {
//那么创建一个与该参数大小相等的数组赋值到存储数据的数组中
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) { //如果传的参数等于0
//将空数组赋值到存储数据的数组中
this.elementData = EMPTY_ELEMENTDATA;
} else {
//否则的话抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
第1次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) {
//size默认为0
//ensureCapacityInternal(0 + 1)
ensureCapacityInternal(size + 1); // Increments modCount!!
//list[0] = e
//size++ = 1
elementData[size++] = e;
return true;
}
//此时minCapacity参数为:1
private void ensureCapacityInternal(int minCapacity) {
//elementData在无参构造的时候赋值为:DEFAULTCAPACITY_EMPTY_ELEMENTDATA
//calculateCapacity(DEFAULTCAPACITY_EMPTY_ELEMENTDATA, 1)
//ensureExplicitCapacity(10)
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//此时elementData参数为:DEFAULTCAPACITY_EMPTY_ELEMENTDATA;minCapacity参数为:1
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//第一次add的时候入了此判断
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//Math.max(10, 1)
//return 10;
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//此时minCapacity参数为:10
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//10 - 0 = 10 > 0进入判断
if (minCapacity - elementData.length > 0)
grow(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
*/
//此时minCapacity参数为:10
private void grow(int minCapacity) {
// overflow-conscious code
//oldCapacity = 0
int oldCapacity = elementData.length;
//这里有个>>概念 叫按位右移运算符
//oldCapacity >> 1 = 0 >> 1 = 0
//newCapacity = 0 = 0 + 0
//计算新的容量 新容量为 老容量的1.5倍 第一次为0
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 0 - 10 = -10 < 0 进入此判断
if (newCapacity - minCapacity < 0)
//newCapacity = 10
newCapacity = minCapacity;
//10 - (20亿 - 8) < 0 所以不会进入此判断
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//存储list数据的数组为:elementData = new Object[]{null,null,null,null,null,null,null,null,null,null};
elementData = Arrays.copyOf(elementData, newCapacity);
}
第2次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) {
//size = 1
//1 + 1 = 2;
ensureCapacityInternal(size + 1); // Increments modCount!!
//elementData[1] = e
//size++ = 2
elementData[size++] = e;
return true;
}
//minCapacity = 2
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//elementData = {e,null,null,null,null,null,null,null,null,null}
//minCapacity = 2
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//不会进入上面的判断了在这里返回2
return minCapacity;
}
//minCapacity = 2
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//2 - 10 < 0不会进入此判断了
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
第11次add()
public boolean add(E e) {
//size = 10
//10 + 1 = 11
ensureCapacityInternal(size + 1); // Increments modCount!!
//elementData[10] = e;
//size = 11;
elementData[size++] = e;
return true;
}
//minCapacity = 11
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//elementData = {e,e,e,e,e,e,e,e,e,e}
//minCapacity = 11
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//再此返回11
return minCapacity;
}
//minCapacity = 11
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//11 - 10 = 1 > 0进入此判断
if (minCapacity - elementData.length > 0)
//minCapacity = 11
grow(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
*/
//minCapacity = 11
private void grow(int minCapacity) {
// overflow-conscious code
//oldCapacity = 10
int oldCapacity = elementData.length;
//oldCapacity >> 1
//1010 -> 0101 = 5
//10 + 5 = 15
//newCapacity = 15
int newCapacity = oldCapacity + (oldCapacity >> 1);
//15 - 11 = 4 > 0不会进入此判断
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 = {e,e,e,e,e,e,e,e,e,e,null,null,null,null,null}
elementData = Arrays.copyOf(elementData, newCapacity);
}
get()
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
//校验下标
rangeCheck(index);
return elementData(index);
}
/**
* Checks if the given index is in range. If not, throws an appropriate
* runtime exception. This method does *not* check if the index is
* negative: It is always used immediately prior to an array access,
* which throws an ArrayIndexOutOfBoundsException if index is negative.
*/
private void rangeCheck(int index) {
//如果下标大于等于size(数组长度,那么抛异常)
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
set()
/**
* Replaces the element at the specified position in this list with
* the specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
//校验下标索引
rangeCheck(index);
//获得该下标下老的数据
E oldValue = elementData(index);
//给该下标赋新的值
elementData[index] = element;
//返回老的数据
return oldValue;
}
remove()
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
//校验下标索引
rangeCheck(index);
modCount++;
//获取该下标下老的数据
E oldValue = elementData(index);
//elementData = {1,2,3,4,5,6,7,8,9,10};
//比如要删除下标5的值 6
//10 - 5 - 1 = 4
//numMoved = 4
int numMoved = size - index - 1;
//4 > 0进入此判断
if (numMoved > 0)
//源数组 开始下标 目标数组 开始下标 长度
//{1,2,3,4,5,6,7,8,9,10}
//{1,2,3,4,5,7,8,9,10}
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//{1,2,3,4,5,7,8,9,10,null}
elementData[--size] = null; // clear to let GC do its work
//返回没删除之前的数据
return oldValue;
}
FailFast机制
上面在添加、删除的时候,看到过modCount++;代码,那么这个代码是干啥的呢?他是一种快速失败机制,就是为了并发情况下,对象内部结构发生变化的一种防护机制
modCount++;
Demo
import java.util.Iterator;
import java.util.List;
public class ThreadIterator extends Thread{
private List list;
public ThreadIterator(List list) {
this.list = list;
}
@Override
public void run() {
for (Iterator iterator = list.iterator();iterator.hasNext();){
iterator.next();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
import java.util.List;
public class ThreadAdd extends Thread{
private List list;
public ThreadAdd(List list) {
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("循环添加第:" + (i + 1) + "次");
list.add(i);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
import java.util.ArrayList;
import java.util.List;
public class ThreadMain {
private static List list = new ArrayList();
public static void main(String[] args) {
new ThreadAdd(list).start();
new ThreadIterator(list).start();
}
}
运行main方法,会抛出异常
Exception in thread "Thread-1" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
at java.util.ArrayList$Itr.next(ArrayList.java:861)
at ThreadIterator.run(ThreadIterator.java:14)
源码分析
这里会判断modCount和expectedModCount
expectedModCount在初始化时有赋值
意思就是当并发情况下,如果list出现数据安全问题就会抛出【java.util.ConcurrentModificationException】异常
下面画个图理解一下
LinkedList源码分析
LinkedList是一个双向链表,顺序遍历查询比较快,随机查询比较慢。他有一个重要的静态内部类Node
Node
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;
}
}
初始化
//链表长度
transient int size = 0;
/**
* 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;
push(11)第1次
/**
* Pushes an element onto the stack represented by this list. In other
* words, inserts the element at the front of this list.
*
* <p>This method is equivalent to {@link #addFirst}.
*
* @param e the element to push
* @since 1.6
*/
public void push(E e) {
//向头部添加数据
addFirst(e);
}
/**
* Inserts the specified element at the beginning of this list.
*
* @param e the element to add
*/
public void addFirst(E e) {
//向头部添加数据
linkFirst(e);
}
/**
* Links e as first element.
*/
private void linkFirst(E e) {
//f = null
final Node<E> f = first;
//[null]11[null]
final Node<E> newNode = new Node<>(null, e, f);
//first = [null]11[null]
first = newNode;
//第一次push()会进入此判断
if (f == null)
//last = [null]11[null]
last = newNode;
else
f.prev = newNode;
//size = 1
size++;
//modCount = 1
modCount++;
}
[null]11[null]
push(22)第2次
/**
* Pushes an element onto the stack represented by this list. In other
* words, inserts the element at the front of this list.
*
* <p>This method is equivalent to {@link #addFirst}.
*
* @param e the element to push
* @since 1.6
*/
public void push(E e) {
//向头部添加数据
addFirst(e);
}
/**
* Inserts the specified element at the beginning of this list.
*
* @param e the element to add
*/
public void addFirst(E e) {
//向头部添加数据
linkFirst(e);
}
/**
* Links e as first element.
*/
private void linkFirst(E e) {
//f = [null]11[null]
final Node<E> f = first;
//newNode = [null]22[11]
final Node<E> newNode = new Node<>(null, e, f);
//first = [null]22[11]
first = newNode;
if (f == null)
last = newNode;
else //第二次push进入此else
//f = [22]11[null]
f.prev = newNode;
//size = 2
size++;
//modCount = 2
modCount++;
}
[null]22[11] -> [22]11[null]
add(11)第1次
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
//向尾部添加数据
linkLast(e);
return true;
}
/**
* Links e as last element.
*/
void linkLast(E e) {
//l = null
final Node<E> l = last;
//[null]11[null]
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
[null]11[null]
add(22)第2次
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
//向尾部添加数据
linkLast(e);
return true;
}
/**
* Links e as last element.
*/
void linkLast(E e) {
//l = [null]11[null]
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++;
}
[null]11[22] -> [11]22[null]
get()
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
//校验下标
checkElementIndex(index);
return node(index).item;
}
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(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;
}
}
set()
/**
* Replaces the element at the specified position in this list with the
* specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
//检测下标
checkElementIndex(index);
//首先找到传入下标参数的原先值
Node<E> x = node(index);
//获取原先值的元素
E oldVal = x.item;
//将原先值赋值为传入的值
x.item = element;
//返回原先值的元素
return oldVal;
}
Vector源码分析
add()
/**
* Appends the specified element to the end of this Vector.
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
我们可以看到,方法修饰上有个synchronized方法,所以vector是线程安全的。它既然是线程安全的,必然性能就比较低
list不是线程安全的,如果要求必须是线程安全的,怎么处理?
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ThreadMain {
private static List list = new ArrayList();
public static void main(String[] args) {
List list = Collections.synchronizedList(ThreadMain.list);
}
}
可以用Collections工具类做一个灵活的转换,转换成线程安全的list
/**
* Returns a synchronized (thread-safe) list backed by the specified
* list. In order to guarantee serial access, it is critical that
* <strong>all</strong> access to the backing list is accomplished
* through the returned list.<p>
*
* It is imperative that the user manually synchronize on the returned
* list when iterating over it:
* <pre>
* List list = Collections.synchronizedList(new ArrayList());
* ...
* synchronized (list) {
* Iterator i = list.iterator(); // Must be in synchronized block
* while (i.hasNext())
* foo(i.next());
* }
* </pre>
* Failure to follow this advice may result in non-deterministic behavior.
*
* <p>The returned list will be serializable if the specified list is
* serializable.
*
* @param <T> the class of the objects in the list
* @param list the list to be "wrapped" in a synchronized list.
* @return a synchronized view of the specified list.
*/
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
我们可以看到相当于把list的get、set、add、remove方法重写了一遍,加了锁
Set接口
HashSet
源码分析
无参构造
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
add()
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
可以看出来HashSet本质上是一个HashMap,所以我们下面分析HashMap其实就知道HashSet的原理了
TreeSet
源码分析
无参构造
/**
* Constructs a new, empty tree set, sorted according to the
* natural ordering of its elements. All elements inserted into
* the set must implement the {@link Comparable} interface.
* Furthermore, all such elements must be <i>mutually
* comparable</i>: {@code e1.compareTo(e2)} must not throw a
* {@code ClassCastException} for any elements {@code e1} and
* {@code e2} in the set. If the user attempts to add an element
* to the set that violates this constraint (for example, the user
* attempts to add a string element to a set whose elements are
* integers), the {@code add} call will throw a
* {@code ClassCastException}.
*/
public TreeSet() {
this(new TreeMap<E,Object>());
}
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element {@code e} to this set if
* the set contains no element {@code e2} such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns {@code false}.
*
* @param e element to be added to this set
* @return {@code true} if this set did not already contain the specified
* element
* @throws ClassCastException if the specified object cannot be compared
* with the elements currently in this set
* @throws NullPointerException if the specified element is null
* and this set uses natural ordering, or its comparator
* does not permit null elements
*/
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
可以看出来TreeSet本质上是一个TreeMap,所以我们下面分析TreeMap其实就知道TreeSet的原理了