JAVA - ArrayList
ArrayList介绍
ArrayList是一个容量能够动态增长的可扩展数组,它的基本数据结构是数组,ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别。它继承了抽象类AbstractList,实现了List、RandomAccess, Cloneable, java.io.Serializable接口。
ArrayList默认第一次插入元素时创建大小为10的数组,当超出数组大小限制时会增加50%容量,用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值。在构造ArrayList时指定其容量。
ArrayList的优势在于可以高效随机访问元素-get(i)/set(i,e),直接在数组末尾加入元素—add(e)的性能也高,但是在ArrayList中间插入和删除元素较慢—add(i,e), remove(i),因为要用System.arraycopy()来移动部分受影响的元素。
ArrayList不是线程安全的!一般在单线程中才使用ArrayList,而在多线程中一般使用Vector或者CopyOnWriteArrayList。
ArrayList优点
* 可以动态的增加和减少元素
* 实现了ICollection和IList接口
* 灵活的设置数组的大小
ArrayList的用法
* 类加载
import java.util.List;
import java.util.ArrayList;
* 构造器
ArrayList提供了三个构造器:
public ArrayList();
默认的构造器,构造一个默认初始容量为10的空列表
public ArrayList(ICollection);
用一个ICollection对象来构造,并将该集合的元素添加到ArrayList,这些元素按照该Collection的迭代器返回它们的顺序排列。
public ArrayList(int);
构造一个指定初始容量为0的空列表
* 添加元素
public boolean add(E e);
将元素添加到ArrayList末尾,如果ArrayList的大小已经不满足需求时,那么就将数组变为原长度的1.5倍,之后的把老的数组拷到新的数组里面再添加元素
public void add(int index, E element);
将元素放添加到ArrayList的指定位置,如果当前位置有元素,则向后移动当前位置的元素以及所有后续的元素(将其索引加+1)。其中rangeCheckForAdd(index)方法:检查插入的位置是否大于当前列表的长度,则抛出异常,允许在列表末尾插入元素;ensureCapacityInternal(index)方法:检查当前当前容量是否能够满足需求,如果不满足则重新规划,System.arraycopy()方法将指定位置以及后续的元素向后移动一位
public boolean addAll(Collection<? extends E> c);
按照Collection的迭代器返回的元素顺序,将Collection中的所有元素添加到列表尾部。其中ensureCapacityInternal()方法计算容量是否满足需求,System.arraycopy()方法将Collection的元素添加到列表尾部
public boolean addAll(int index, Collection<? extends E> c)
从指定位置开始,将指定collection的所有元素插入次列表中。其中rangeCheckForAdd(index)方法检测输入位置是否大于列表位置,ensureCapcityIntanal()方法确认容量是否满足需要,如插入位置小于列表长度,则需要将列的指定位置以及后续的元素都移动到插入元素长度以后
List<String> arrayList = new ArrayList<String>();
List<String> insertList = new ArrayList<String>();
arrayList.add("A");
arrayList.add("B");
arrayList.add(0, "C");
insertList.add("O");
insertList.add("P");
arrayList.addAll(insertList);
arrayList.addAll(0, insertList);
for (String str : arrayList)
{
System.out.println(str);
}
* 删除元素
public E remove(int index);
删除指定位置的元素
public boolean remove(Object o);
移除此列表首次出现的指定元素(如果存在),ArrayList可以存放重复的元素。由于可以存储Null,所以要分情况处理。其中fastremove()方法:将移除的位置以后的元素向前移动。并且将最后一位置null
public boolean removeAll(Collection<?> c);
删除ArrayList与集合C的交集部分
List<String> arrayList = new ArrayList<String>();
List<String> insertList = new ArrayList<String>();
arrayList.add("A");
arrayList.add("C");
arrayList.add("B");
arrayList.add("C");
insertList.add("B");
insertList.add("D");
arrayList.remove(0);
arrayList.remove("C");
arrayList.removeAll(insertList);
public void clear();
设置ArrayList各元素的值为null,然后交给gc(垃圾回收)处理
* 替换元素
public E set(int index, E element);
替换指定位置上的元素,index指定下标,element指定要修改后元素的值,并且返回替换之前的指定位置的元素。其中rangeCheck(index)方法是检查指定位置是否大于等于列表长度,如果大于则抛出异常。
* 获取元素
public E get(int index);
* 调整数组容量
public void ensureCapacity(int minCapacity);
ArrayList中数组扩容通过一个此来实现。在实际添加大量元素前,可以通过调用ensureCapacity方法来手动增加ArrayList实例的容量
public void trimToSize();
将底层数组的容量调整为当前列表保存的实际元素的大小的功能.当动态数组元素确定不在添加的时候,可以调用这个方法来释放空余的内存
* 查找元素
public boolean contains(Object o);
用来判断用来查找的元素是否包含在列表中
public int indexOf(Object o);
获得指定元素的最小的索引位置
public int lastIndexOf(Object o);
获得指定元素的最大的索引位置
ArrayList与数组转换
public Object[] toArray();
将ArrayList转换为Object[] 数组,注意将Object[] 数组转化为其他类型数组不可以直接写为String[] array= (String[]) arrayList.toArray(),否则会抛出java.lang.ClassCastException异常,转化的话只能取出每一个元素逐个转化
Object[] arr = arrayList.toArray();
for (int i = 0; i < arr.length; i++) {
String e = (String) arr[i];
System.out.println(e);
}
public <T> T[] toArray(T[] a);
将ArrayList转换为T[] 数组String[] desc = new String[arrayList.size()];
arrayList.toArray(desc);
注:因为可以将ArrayList转换为Object数组,所以往ArrayList里面添加不同类型的元素是不会出错的,但是当调用toArray方法的时候,要么传递所有元素都可以正确转型的类型或者Object类型,否则将会抛出无法转型的java.lang.ClassCastException异常
ArrayList遍历方式
* 索引值遍历随机访问
由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。
for(int i = 0; i < arrayList.size(); i++){
System.out.print(arrayList.get(i) + " ");
}
* foreach语句
foreach语句是JAVA 5的新特征之一,在遍历数组、集合方面,foreach为开发人员提供了极大的方便。
List<String> arrayList = new ArrayList<String>();
for (String str : arrayList)
{
System.out.println(str);
}
* 迭代器遍历
迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,即我们无需关心该序列的底层结构是什么样子的,只要拿到这个对象,使用迭代器就可以遍历这个对象的内部。
Iterator<String> it = arrayList.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
注意:遍历ArrayList时,通过索引值遍历效率最高,迭代器遍历次之,foreach遍历最低。ArrayList实现了RandomAccess接口,实现RandomAccess接口的集合类,使用for循环的效率会比Iterator高。而foreach不是关键字,它的关键字是for,它的语句是由Iterator实现的,foreach就是为了让用Iterator循环访问的形式简单。