ArrayList底层是用数组实现的存储。
查询的效率高,增删效率低,线程不安全。
属性及构造方法
// 默认容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 未初始化的空数组
transient Object[] elementData; // non-private to simplify nested class access
// 容量大小
private int size;
/**
* ArrayList指定长度构造方法
*/
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);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
* 无参构造方法
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 参数为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;
}
}
当我们使用无参的构造方法时,会给elementData赋值一个空数组,容量大小是0,并不是注释上说的10,真正意义上分配大小的时候,是执行add()方法的时候。为什么注释会写分配了10呢,因为JDK1.7以前初始化的时候默认会调this(10),分配容量,忘记改了吧。
常用方法
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;
}
remove()方法在这里插入代码片
remove方法和add方法很类似,也是采用数组copy的方法,将指定下标后一位到数组末尾的全部元素向前移一位。然后把最后一个元素设置为null。容量保持不变。
set()方法
set(int index, E element)方法的作用是指定下标索引处的元素的值。在ArrayList的源码实现中,方法内首先判断传递的元素数组下标参数是否合法,然后将原来的值取出,设置为新的值,将旧值作为返回值返回。
ArrayList<Integer> list = new ArrayList<Integer>();
list.set(0,0);
这样子使用会报错,原因如下
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
线程安全性
因为在add()方法的时候,在index位置添加元素,和size++并不是原子性的,分成了添加元素和size++ 两个步骤。
假设有一个ArrayList,size = 1,此时有两个线程对他操作,第一个线程已经把元素添加到ArrayList的第二个位置上进去了,但是还没有执行size++操作,此时另一个线程进来添加元素,由于现在的size还是1,添加的位置还是第二个。然后两个线程再执行size++操作,而实际上ArrayList只有一个元素,所以ArrayList线程不安全。