一、ArrayList
泛型容器,内部有一个数组elementData,有一个整数size记录实际的元素个数。
1、扩容操作
1)新增元素add(E e)
minCapacity:最小容量,size+1;
如果minCapacity-elementData.length>0;就需要扩容;
newCapacity:elementData.length+(elementData.length>>1),1.5倍与原来容量的大小;
如果newCapacity与minCapacity比较,哪个大用哪个进行扩容,
Arrays.copyOf(elementData,newCapacity):复制到新数组。
2)删除元素remove(index)
int numMoved=size-index-1;计算要移动的元素个数
System.arraycopy(elementData,index+1,elementData,index,numMoved);从index往后的元素都向前移动一位
elementData[- -index]=null;将size-1,同时释放引用以便原对象被垃圾回收
2、迭代操作
foreach():使用用容器,容器只要实现了Iterable接口,就可以使用foreach语法,编译器会转换为调用Iterable和Iterator接口。
Iterator接口:
public interface Iterator<E>{
boolean hasNext();//判断是否有元素未访问
E next();//返回下一个元素
void remove();//删除最后返回的元素
}
使用foreach遍历删除元素(list.remove())会抛出并发修改异常,需要注意。
原因:因为迭代器内部维护一些索引位置相关的数据,要求在迭代过程中,容器不能发生结构型变化,否则这些索引位置就会失效。结构型变化:添加、插入和删除元素(使用ArrayList的 add、remove),修改元素内容不算结构型变化。可以使用Iterator.remove()进行删除。
二、ArrayList实现的接口
ArrayList还实现了三个主要的接口:Collection、List和RandomAccess
1、Collection
表示一个数据集合,数据间没有位置或顺序的概念;
2、List
表示有顺序或位置的数据集合,扩展了Collection
3、RandomAccess
这是一个空接口,在java中被称为标记接口,用于声明类的一种属性,实现了RandomAccess接口的类表示类可以随机访问,表明数据在内存中时连续存放的,可以根据索引值直接定位到具体的元素。
public Object[] toArray();
public T[] toArray(T[] a);
第一个返回数组方法是返回一个Object数组
第二个返回对应类型的数组,如果参数数组长度足以容纳所有元素,就是用该数组,否则就新建一个数组。需要注意的是,a的长度大于arrayList长度时,只会将a[size]=null,后面元素不为设置为null。
三、Arrays工具类
数组工具类,
List Arrays.asList<T[] a>
这个方法返回的ArrayList是Arrays类的一个内部类,在这个内部类的实现中,内部用的数组就是传入的数组,没有拷贝,也没有动态的改变大小,所以对数组的修改就会反映到List中,对List调用add、remove会抛出异常。(这个内部类add和remove方法直接抛出异常)
要使用ArrayList完整的方法,应该新建一个ArrayList
List list=new ArrayList(Arrays.asList(a));
四、总结
ArrayList
1、可以随机访问
2、查找元素、添加元素可以;
3、插入或者删除元素效率低