ArrayList简介:
ArrayList底层实现其实是基于一个动态数组,每当我们添加元素时都会判断数组容量是否足够,如果不足则对数组进行扩容。这个数组默认长度为10,当然我们也可以设定数组的长度。每次扩容是基于原有长度的1.5倍。并且ArrayList是非线程安全的。
看下ArrayList的构造函数源码,ArrayList一共有三个构造函数:
//elementData就是存放元素的数组
private transient Object[] elementData;
//size标记元素个数
private int size;
/**
* Constructs an empty list with an initial capacity of ten.
* 初始化一个长度为10的空数组
*/
public ArrayList() {
this(10);
}
/**
* Constructs an empty list with an initial capacity of ten.
* 初始化一个指定长度的空数组
*/
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//初始化数组
this.elementData = new Object[initialCapacity];
}
public ArrayList(Collection<? extends E> c) {
//初始化数组
elementData = c.toArray();
//元素个数
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
第一个构造函数创建一个默认为10的空数组
第二个构造函数创建一个指定长度的空数组
第三个构造函数创建一个有初始值的数组
get()方法源码分析:
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
get()方法很好理解: rangeCheck(index)判断index是否越界,是的话抛出异常,不是则返回数据
add()方法源码分析:
public boolean add(E e) {
ensureCapacityInternal(size + 1); //判断容量,size=元素个数,当数组满后size和数组长度一样
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// 判断数组容量是否足够
if (minCapacity - elementData.length > 0)
//grow方法进行扩容
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//计算扩容后的数组长度
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 数组扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
你可以看到每次调用add(),都会进行判断数组是否已满,不满直接添加,如果满了则进行扩容。
addAll()方法源码解析:
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
//获取传入的集合长度
int numNew = a.length;
//判断数组容量是否足够
ensureCapacityInternal(size + numNew);
//把数组a复制添加到elementData的末尾
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
remove()方法源码解析:
public E remove(int index) {
//判断是否越界,越界则抛异常
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
//将elementData从index+1下标开始复制numMoved个数据到elementData的index下标开始
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//将数组最后位置值null,等待回收
elementData[--size] = null; // Let gc do its work
return oldValue;
}
ArrayList源码当中数组扩容是通过Arrays.copyOf()、添加和删除是通过System.arraycopy()。可以看我另外一边博客介绍这俩个方法的用法:Arrays.copyOf()和System.arraycopy()的用法
最后对ArrayList的总结:
1.ArrayList是非线程安全的
2.ArrayList默认会创建一个长度为10的数组,每次扩容是基于原来长度的1.5倍
3.ArrayList是基于数组实现的,支持随机访问,查找效率高,但是插入删除效率低。
ArrayList实现线程安全:
List<String> list= Collections.synchronizedList(new ArrayList<String>());