一、概念
类定义:
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
- 继承了AbstractList抽象类,实现了List接口,拥有一组List通用的操作。
- 实现了RandomAccess接口,可进行随机访问。
- 实现了Cloneable接口,可进行浅层次拷贝。
- 实现了Serializable接口,可进行序列化。
特点:
- 长于随机访问元素。
- 在List中间插入和删除元素较慢。
二、使用
//TestArrayList
public class TestArrayList {
private static final String TAG = "TestArrayList";
private ArrayList list = new ArrayList<>();
public void testAdd() {
list.add("a");
list.add("b");
list.add("c");
Log.d(TAG, "zwm, add list: " + list);
}
public void testGet() {
Log.d(TAG, "zwm, get index 2: " + list.get(2));
}
public void testAdd2() {
list.add(0, "ii");
list.add(1, "jj");
list.add(2, "kk");
Log.d(TAG, "zwm, add index list: " + list);
}
public void testAddAll() {
ArrayList temp = new ArrayList<>();
temp.add("lll");
temp.add("mmm");
temp.add("nnn");
list.addAll(temp);
Log.d(TAG, "zwm, addAll list: " + list);
}
public void testAddAll2() {
ArrayList temp = new ArrayList<>();
temp.add("xxxx");
temp.add("zzzz");
temp.add("yyyy");
temp.add("zzzz");
list.addAll(0, temp);
Log.d(TAG, "zwm, addAll index list: " + list);
}
public void testIndexOf() {
Log.d(TAG, "zwm, indexOf zzzz: " + list.indexOf("zzzz"));
}
public void testLastIndexOf() {
Log.d(TAG, "zwm, lastIndexOf zzzz: " + list.lastIndexOf("zzzz"));
}
public void testClone() {
ArrayList cloneList = (ArrayList)list.clone();
Log.d(TAG, "zwm, list.equals(cloneList): " + list.equals(cloneList));
Log.d(TAG, "zwm, list==cloneList: " + (list==cloneList));
}
public void testContains() {
Log.d(TAG, "zwm, contains zzzz: " + list.contains("zzzz"));
}
public void testContainsAll() {
ArrayList temp = new ArrayList<>();
temp.add("xxxx");
temp.add("yyyy");
temp.add("zzzz");
Log.d(TAG, "zwm, containsAll: " + list.containsAll(temp));
}
public void testSize() {
Log.d(TAG, "zwm, size: " + list.size());
}
public void testClear() {
list.clear();
Log.d(TAG, "zwm, clear list: " + list);
}
public void testEmpty() {
Log.d(TAG, "zwm, isEmpty: " + list.isEmpty());
}
public void testIterator() {
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Log.d(TAG, "zwm, iterator item: " + iterator.next());
}
}
public void testIterator2() {
ListIterator iterator = list.listIterator();
while (iterator.hasNext()) {
String item = iterator.next();
Log.d(TAG, "zwm, listIterator item: " + item);
if(TextUtils.equals(item, "b")) {
Log.d(TAG, "zwm, remove b");
iterator.remove();
} else if(TextUtils.equals(item, "c")) {
Log.d(TAG, "zwm, update c to x");
iterator.set("x");
}
}
Log.d(TAG, "zwm, listIterator list: " + list);
Log.d(TAG, "zwm, next index: " + iterator.nextIndex());
Log.d(TAG, "zwm, previous index: " + iterator.previousIndex());
while(iterator.hasPrevious()) {
String item = iterator.previous();
Log.d(TAG, "zwm, listIterator item: " + item);
}
}
public void testIterator3() {
ListIterator iterator = list.listIterator(2);
while (iterator.hasNext()) {
String item = iterator.next();
Log.d(TAG, "zwm, listIterator index item: " + item);
}
}
public void testRemove() {
Log.d(TAG, "zwm, remove a: " + list.remove("a"));
Log.d(TAG, "zwm, remove list: " + list);
}
public void testRemove2() {
Log.d(TAG, "zwm, remove index 3: " + list.remove(3));
Log.d(TAG, "zwm, remove index list: " + list);
}
public void testRemoveAll() {
ArrayList temp = new ArrayList<>();
temp.add("a");
temp.add("b");
Log.d(TAG, "zwm, removeAll: " + list.removeAll(temp));
Log.d(TAG, "zwm, removeAll list: " + list);
}
public void testRetainAll() {
ArrayList temp = new ArrayList<>();
temp.add("a");
temp.add("b");
temp.add("c");
Log.d(TAG, "zwm, retainAll: " + list.retainAll(temp));
Log.d(TAG, "zwm, retainAll list: " + list);
}
public void testSet() {
list.set(0, "sss");
Log.d(TAG, "zwm, set list: " + list);
}
public void testSubList() {
//以下注释语句会抛出异常java.lang.ClassCastException: java.util.ArrayList$SubList cannot be cast to java.util.ArrayList
//ArrayList subList = (ArrayList)list.subList(1, 2);
List subList = list.subList(1, 3);
Log.d(TAG, "zwm, subList: " + subList);
}
public void testEnsureCapacity() {
//在数据量过大的情况下初始化理想的ArryList容量,效率会明显高于自动扩容
//所以在项目中有些业务处理时候对ArryList的长度有明显的把控时 最好自定义其扩容方法来提高程序的执行效率
Log.d(TAG, "zwm, ensureCapacity");
list.ensureCapacity(100);
}
public void testTrimToSize() {
//将ArrayList容量设置为实际大小
Log.d(TAG, "zwm, trimToSize");
list.trimToSize();
}
public void testToArray() {
Object[] arrays = list.toArray();
for(Object item : arrays) {
Log.d(TAG, "zwm, toArray item: " + item);
}
}
public void testToArray2() {
String[] param = new String[list.size()];
String[] result = list.toArray(param);
for(String item : param) {
Log.d(TAG, "zwm, toArray T param item: " + item);
}
for(String item : result) {
Log.d(TAG, "zwm, for result T result item: " + item);
}
}
}
//测试代码
private void testMethod() {
Log.d(TAG, "zwm, testMethod");
TestArrayList testArrayList = new TestArrayList();
testArrayList.testAdd();
testArrayList.testAdd2();
testArrayList.testAddAll();
testArrayList.testAddAll2();
testArrayList.testGet();
testArrayList.testIndexOf();
testArrayList.testLastIndexOf();
testArrayList.testClone();
testArrayList.testContains();
testArrayList.testContainsAll();
testArrayList.testSize();
testArrayList.testClear();
testArrayList.testEmpty();
testArrayList.testAdd();
testArrayList.testIterator();
testArrayList.testIterator2();
testArrayList.testAdd();
testArrayList.testIterator3();
testArrayList.testEnsureCapacity();
testArrayList.testRemove();
testArrayList.testRemove2();
testArrayList.testRemoveAll();
testArrayList.testAdd();
testArrayList.testRetainAll();
testArrayList.testSet();
testArrayList.testSubList();
testArrayList.testTrimToSize();
testArrayList.testToArray();
testArrayList.testToArray2();
}
//输出log
2019-08-02 18:31:06.908 zwm, testMethod
2019-08-02 18:31:06.911 zwm, add list: [a, b, c]
2019-08-02 18:31:06.912 zwm, add index list: [ii, jj, kk, a, b, c]
2019-08-02 18:31:06.912 zwm, addAll list: [ii, jj, kk, a, b, c, lll, mmm, nnn]
2019-08-02 18:31:06.913 zwm, addAll index list: [xxxx, zzzz, yyyy, zzzz, ii, jj, kk, a, b, c, lll, mmm, nnn]
2019-08-02 18:31:06.913 zwm, get index 2: yyyy
2019-08-02 18:31:06.913 zwm, indexOf zzzz: 1
2019-08-02 18:31:06.913 zwm, lastIndexOf zzzz: 3
2019-08-02 18:31:06.914 zwm, list.equals(cloneList): true
2019-08-02 18:31:06.914 zwm, list==cloneList: false
2019-08-02 18:31:06.914 zwm, contains zzzz: true
2019-08-02 18:31:06.914 zwm, containsAll: true
2019-08-02 18:31:06.914 zwm, size: 13
2019-08-02 18:31:06.914 zwm, clear list: []
2019-08-02 18:31:06.915 zwm, isEmpty: true
2019-08-02 18:31:06.915 zwm, add list: [a, b, c]
2019-08-02 18:31:06.915 zwm, iterator item: a
2019-08-02 18:31:06.915 zwm, iterator item: b
2019-08-02 18:31:06.915 zwm, iterator item: c
2019-08-02 18:31:06.915 zwm, listIterator item: a
2019-08-02 18:31:06.915 zwm, listIterator item: b
2019-08-02 18:31:06.915 zwm, remove b
2019-08-02 18:31:06.916 zwm, listIterator item: c
2019-08-02 18:31:06.916 zwm, update c to x
2019-08-02 18:31:06.916 zwm, listIterator list: [a, x]
2019-08-02 18:31:06.916 zwm, next index: 2
2019-08-02 18:31:06.916 zwm, previous index: 1
2019-08-02 18:31:06.916 zwm, listIterator item: x
2019-08-02 18:31:06.916 zwm, listIterator item: a
2019-08-02 18:31:06.916 zwm, add list: [a, x, a, b, c]
2019-08-02 18:31:06.917 zwm, listIterator index item: a
2019-08-02 18:31:06.917 zwm, listIterator index item: b
2019-08-02 18:31:06.917 zwm, listIterator index item: c
2019-08-02 18:31:06.917 zwm, ensureCapacity
2019-08-02 18:31:06.917 zwm, remove a: true
2019-08-02 18:31:06.917 zwm, remove list: [x, a, b, c]
2019-08-02 18:31:06.918 zwm, remove index 3: c
2019-08-02 18:31:06.918 zwm, remove index list: [x, a, b]
2019-08-02 18:31:06.918 zwm, removeAll: true
2019-08-02 18:31:06.918 zwm, removeAll list: [x]
2019-08-02 18:31:06.918 zwm, add list: [x, a, b, c]
2019-08-02 18:31:06.919 zwm, retainAll: true
2019-08-02 18:31:06.919 zwm, retainAll list: [a, b, c]
2019-08-02 18:31:06.919 zwm, set list: [sss, b, c]
2019-08-02 18:31:06.919 zwm, subList: [b, c]
2019-08-02 18:31:06.920 zwm, trimToSize
2019-08-02 18:31:06.920 zwm, toArray item: sss
2019-08-02 18:31:06.920 zwm, toArray item: b
2019-08-02 18:31:06.920 zwm, toArray item: c
2019-08-02 18:31:06.920 zwm, toArray T param item: sss
2019-08-02 18:31:06.920 zwm, toArray T param item: b
2019-08-02 18:31:06.920 zwm, toArray T param item: c
2019-08-02 18:31:06.920 zwm, toArray T result item: sss
2019-08-02 18:31:06.920 zwm, toArray T result item: b
2019-08-02 18:31:06.921 zwm, toArray T result item: c
三、原理
重要参数
//默认的数组长度
private static final int DEFAULT_CAPACITY = 10;
//默认的空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认的空数组(与EMPTY_ELEMENTDATA有点区别,在不同的构造函数中用到)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//真正用于存放数据的数组
transient Object[] elementData;
//数组元素个数
private int size;
构造函数
//指定容量大小初始化
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);
}
}
//无参初始化,DEFAULTCAPACITY_EMPTY_ELEMENTDATA与EMPTY_ELEMENTDATA都是空数组,区别是当第一个元素被插入时,如果使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,会自动将容量扩容到10
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//构造一个包含指定Collection的元素的列表,这些元素是按照该Collection的迭代器返回它们的顺序排列的
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;
}
}
public void trimToSize()
//将ArrayList容量设置为实际大小
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size); //拷贝数组elementData,新数组大小为size
}
}
public void ensureCapacity(int minCapacity)
//在数据量过大的情况下初始化理想的ArryList容量,效率会明显高于自动扩容
//所以在项目中有些业务处理时候对ArryList的长度有明显的把控时 最好自定义其扩容方法来提高程序的执行效率
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0) //如果指定的minCapacity数值比当前数组容量大,则进行扩容
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //newCapacity赋值为oldCapacity * 1.5
if (newCapacity - minCapacity < 0) //如果newCapacity小于指定的minCapacity数值,则newCapacity赋值为minCapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) //如果newCapacity大于MAX_ARRAY_SIZE
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity); //拷贝数组elementData,新数组大小为newCapacity
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? //如果指定的minCapacity数值大于MAX_ARRAY_SIZE,则扩容至Integer.MAX_VALUE,否则使用MAX_ARRAY_SIZE
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
private void ensureCapacityInternal(int minCapacity)
//在相关操作之前,确保数组有足够的容量
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
public boolean add(E e)
//添加一个元素在数组末尾
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public void add(int index, E element)
//在索引位置插入元素
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1, //将index及后面的数据后移一位
size - index);
elementData[index] = element; //插入元素到index位置
size++; //元素个数加1
}
//判断索引是否越界
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
public boolean addAll(Collection extends E> c)
//插入Collection中的所有元素到末尾
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); //拷贝数组a的numNew个元素到数组elementData的末尾
size += numNew; //元素个数加numNew
return numNew != 0;
}
public boolean addAll(int index, Collection extends E> c)
//在索引位置插入Collection中的所有元素
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, //将index及后面的数据后移numNew位
numMoved);
System.arraycopy(a, 0, elementData, index, numNew); //拷贝数组a的numNew个元素到数组elementData的以index开始的numNew个位置
size += numNew;
return numNew != 0;
}
public E remove(int index)
//输出索引位置的元素
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, //将index后面的元素前移一位
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
public boolean remove(Object o)
//删除与对象o相等的元素
public boolean remove(Object o) {
if (o == null) { //要删除的为空对象
for (int index = 0; index < size; index++)
if (elementData[index] == null) { //判断是否等于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, //将index后面的元素前移一位
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
public boolean removeAll(Collection> c)
//删除Collection中有的所有元素
public boolean removeAll(Collection> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
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;
}
public E set(int index, E element)
//修改索引位置的元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
public E get(int index)
//查询索引位置的元素
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
public int indexOf(Object o)
//查询第一个与对象o相等的元素的索引位置
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
public int lastIndexOf(Object o)
//查询最后一个与对象o相等的元素的索引位置
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
public boolean contains(Object o)
//查询是否包含与对象o相等的元素
public boolean contains(Object o) {
return indexOf(o) >= 0; //调用indexof方法
}
public void clear()
//清空数组
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
public int size()
//获取数组元素个数
public int size() {
return size;
}
public boolean isEmpty()
//判断数组是否有元素
public boolean isEmpty() {
return size == 0;
}
public Iterator iterator()
//返回迭代器对象
public Iterator iterator() {
return new Itr();
}
//迭代器类,实现了Iterator接口
private class Itr implements Iterator {
//获取下一个元素
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
//移除当前元素
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
//确认是否在别的线程有修改集合
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
fail-fast机制:
在next和remove操作之前,都会调用checkForComodification函数,如果modCount和本身记录的expectedModCount不一致,就证明集合在别处被修改过,抛出ConcurrentModificationException异常,产生fail-fast事件。
fail-fast机制是java集合(Collection)中的一种错误机制,当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了,那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。一般在多线程环境下,可以考虑使用CopyOnWriteArrayList来避免fail-fast。
public ListIterator listIterator()
//返回迭代器对象
public ListIterator listIterator() {
return new ListItr(0);
}
//迭代器类,实现了ListIterator接口
private class ListItr extends Itr implements ListIterator
四、主题
数组