ArrayList:
是List的一个具体实现子类,是List接口的一个数组实现 (里面必定维护了一个数组)。
默认初始容量10, 扩容机制1.5倍。(数组必然有初始容量和扩容机制)
有序。
允许null元素。
允许重复元素。
线程不安全。
add 增加
contains 判断是否存在
get 获取指定位置的对象
indexOf 获取对象所处的位置
remove 删除
set 替换
size 获取大小
toArray 转换为数组
addAll 把另一个容器所有对象都加进来
clear 清空
3.重点源码分析
源码解析:
import java.util.Arrays; import java.util.ConcurrentModificationException; public class MyArrayList<E>{ private static final int DEFAULT_CAPACITY = 10;// 默认容量 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 最大容量 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA ={} ;//空数组 private Object[] elements;//底层维护的数组 private int size;//容器内对象的个数 private int modCount;//记录ArrayList这个对象被修改的次数 //构造方法 public MyArrayList() { this.elements = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //获取列表存的数据量 public int getSize() { return size; } /** *增加内容 * @param e * @return */ public boolean add(E e) { //创建一个默认为10的数组,若小则扩容 ensureCapacityInternal(size+1); //确保容量够,则添加数据,并讲数据大小加1. elements[size]=e; size++; return true; } //该方法来确保数组的容量够用,若为创建则创建数组并赋予默认值。 private void ensureCapacityInternal(int minCapacity) { //若数组为空(还未添加数据) if (elements==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){ //则选出默认值和最小容量的最大值 minCapacity=Math.max(DEFAULT_CAPACITY,minCapacity); //只add方法其实没必要比较,主要是addAll()这个方法需要比较 } modCount++;//修改次数加一 //判断一下是否需要扩容,若数据+1大于当前数组,则需要扩容 if(minCapacity-elements.length>0){ grow(minCapacity);//调用扩容方法 } } /** * 具体的扩容方法 * @param minCapacity */ private void grow(int minCapacity){ int oldCapacity=elements.length;//获取原始数组的长度 int newCapacity=oldCapacity+(oldCapacity>>1);//扩容 1+0.5 倍 //若扩容后的长度比所需要的最低长度还要小,则直接把扩容的长度更改为最低所需长度 if (newCapacity-minCapacity<0){ newCapacity=minCapacity; } //若扩容完的新长度比规定的最大容量还大,则要进一步判断,并进一步修改数组大小 if (newCapacity-MAX_ARRAY_SIZE>0){ //若所需的容量竟然小于0,说明超过Int最大值,越界了,抛出异常 if (minCapacity<0){ throw new OutOfMemoryError(); } //若所需的容量不超过Int最大值,则再判断 if (minCapacity>MAX_ARRAY_SIZE){//若所需的大于数组要求的而小于Int最大值 newCapacity=Integer.MAX_VALUE;//直接赋值Int最大值 }else{//否则只有小于数组最大值这一种情况了,赋予数组最大值即可 newCapacity=MAX_ARRAY_SIZE; } } elements = new Object[newCapacity]; } /** * 根据下标添加元素 * @param index 下标 * @param element 要替换的元素 */ public void add(int index,E element){ //先检查一下下标是否越界 rangeCheck(index); //确保数组长度够用 ensureCapacityInternal(size+1); //这里调用System里面一个静态的本地方法(效率更高),用于数组的复制。这里把下标后面的都向后移了。 /* public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); Object src:the source array. 源数组 int srcPos:starting position in the source array. 在源数组中,开始复制的位置 Object dest:the destination array. 目标数组 int destPos:starting position in the destination data. 在目标数组中,开始赋值的位置 int length:the number of array elements to be copied. 被复制的数组元素的数量*/ System.arraycopy(element, index, element, index + 1, size - index);//等于说把下标后面的都向后移了。 //原数组 开始的位置 目标数组 目标数组中开始复制的位置 被复制的数量 //由于下标后的都往后移动了一位,因此index的位置为空,插进去即可 elements[index]=element; size++; } /** * 检查下标是否越界 * @param index */ private void rangeCheck(int index) { if (index>size||index<0){//若插入的下标比数据实际数量大或者输入的是个不合常理的负数 throw new IndexOutOfBoundsException((outOfBoundsMsg(index)));//抛出异常并返回要插入的下标数和实际数据的数量 } } /** * 用于越界异常的信息抛出 * @param index 输入下标 * @return 返回下标和实际数据的数量大小 */ private String outOfBoundsMsg(int index) { return "Index:"+index+",Size:"+size; } /** * 清空列表所有元素 * 由垃圾回收器(GC)进行回收 */ public void clear(){ //记录对象修改次数 modCount++; //让数组所有的数据都变为null, clear to let GC do its work for (int i=0;i<size;i++){ elements[i]=null; } //这时长度都为0了 size=0; } /** * 根据下标更改数据 * @param index 下标 * @param element 想要更改的数据 * @return 返回原始数据 */ public E set(int index, E element) { //首先判断是否越界 rangeCheck(index); E oldValue= (E) elements[index]; elements[index]=element; return oldValue; } /** * 检查操作数是否一致,防止并发修改错误 *//* private void checkForComodification() { if (MyArrayList.this.modCount != this.modCount)//线程中的和保存的数据不一样 throw new ConcurrentModificationException();//不一致则抛出异常 }*/ /** * 简简单单的根据下标查询数据操作 * @param index 下标 * @return 返回数据信息 */ public E get(int index) { rangeCheck(index); return (E) elements[index]; } /** * 根据下标删除元素 * @param index 要删除的下标 * @return 返回要删除的数据 */ public E remove (int index){ rangeCheck(index);//检查一下下标是否合适 modCount++;//操作数加一 E oldValue= (E) elements[index]; //定义numMoved,记录一下index后面的数,等会要把他们都移动了 int numMoved=size-index-1; if (numMoved>0){ System.arraycopy(elements,index+1,elements,index,numMoved);//通过本地静态的复制方法,来实现数据的前移。 } elements[size]=null;//都前移了以后原本最后一位数的内存设为null,让GC回收了 clear to let GC do its work size--; return oldValue; } /** * 找到相应的元素并对其进行删除 * @param o * @return 返回true表示删除完成,false表示删除失败 */ public boolean remove(Object o) { if (o == null) {//删除null数据 for (int index = 0; index < size; index++) if (elements[index] == null) { fastRemove(index); return true; } } else {//删除正常的数据 for (int index = 0; index < size; index++) if (o.equals(elements[index])) { fastRemove(index); return true; } } return false;//若没找到该数据则返回false } /** * 无需进行判断下标是否合适的快速删除方法 * @param index */ private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elements, index+1, elements, index, numMoved); elements[--size] = null; // clear to let GC do its work } /** * 判断数据是否为空(列表里没数据) * @return 若为空则返回true */ public boolean isEmpty() { return size == 0; } /** * 查询是否有该数据 * @param o * @return 若有返回true */ public boolean contains(Object o) { return indexOf(o) >= 0;//若该索引为正,则表明有该数据,且第一次出现的位置在indexOf } /** *返回指定元素的第一次出现的索引 * @param o * @return 若存在则返回第一次出现的位置,若没有则返回-1 */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elements[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elements[i])) return i; } return -1; } /** *返回指定元素的最后一次出现的索引 * @param o * @return 若存在则返回最后一次出现的位置,若没有则返回-1 */ public int lastIndexOf(Object o) { if (o == null) { for (int i = size-1; i >= 0; i--)//从后向前遍历即可 if (elements[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elements[i])) return i; } return -1; } @Override public String toString() { return "MyArrayList{" + "elements=" + Arrays.toString(elements) + '}'; } }