ArrayList相当于一个动态数组,可以根据需要改变其数组长度。
ArrayList的属性分析:
// 序列化id private static final long serialVersionUID = 8683452581122892189L; // 存储arraylist元素的数组缓冲区 private transient Object[] elementData; // 当前数组长度 private int size; //数组的最大尺寸,有些虚拟机在数组中存储一些数据头 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
ArrayList的继承关系 :
public class ArrayList<E> extends AbstractList<E> //父类 implements List<E>, RandomAccess, Cloneable, Serializable //接口
一 :由于他继承了AbstractList抽象类,AbstractList又继承了List接口。故ArrayList对象中存在List接口增删改查操作。
二:ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。
三,ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
四,ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。当然会有transisent关键字限制变量。
源码分析:
三种构造函数:
//构造函数一 public ArrayList() { this(10); //调用ArrayList(10) 默认初始化一个大小为10的object数组。 } //构造函数二 public ArrayList(int initialCapacity) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); //如果用户初始化大小小于0抛异常,否则新建一个用户初始值大小的object数组。 this.elementData = new Object[initialCapacity]; } //构造函数三 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // 当c.toArray返回的不是object类型的数组时,进行下面转化。 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }
增添:add(Object obj)方法
//1----------------------- public boolean add(E e) { ensureCapacityInternal(size + 1); // 加入元素前检查数组的容量是否足够 elementData[size++] = e; return true; } //2----------------------- private void ensureCapacityInternal(int minCapacity) { modCount++; // 如果添加元素后大于当前数组的长度,则进行扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); } //3----------------------- private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //将数组的长度增加原来数组的一半。 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果扩充一半后仍然不够,则 newCapacity = minCapacity;minCapacity实际元素的个数。 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //数组最大位2^32 // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
注意此处的modcount计数器:他是一个记录arraylist对象操作次数的变量。
那么记录他有什么用?
1. List有个迭代器
2. 在迭代的过程中,每次都要查一下modCount是否变化
3. 如果变化了,迭代器在处理时可能出现不可预知的情况。因此只要这个值变化了,迭代器就抛出异常
4. 所以modCount的作用是迭代器在遍历时做线程安全检查的。
补充一点add(int index,Object obj)的代码解析:
add(int index,Object obj){ rangeCheckForAdd(index); //判断index是否在数组下标中 ensureCapacityInternal(int mincapacity) //检查是否需要扩容 System.arrayCopy(object str ,int strpos ,object dest ,int destpos,int length ) elementdata[index]= obj; size++; }
这里必须要提一下System.arrayCopy()参数列表:
object str:源数组;int strpos: 要复制数组的起始点;object dest:目标数组;int destpos:目标数组的起始get点i;
int length:要被复制的数组长度
删除源码:remove(int index)
public E remove(int index) { rangeCheck(index); //如果index>=size抛出异常 modCount++; E oldValue = elementData(index); //获取删除元素的值 int numMoved = size - index - 1; //将index后面所有的元素往前移一位。 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work //返回要删除的原数。 return oldValue; }
remove(object obj):
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastremove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastremove(index); return true; } } return false; }
fastRemove与Remove区别:
// 快速删除第index个元素 private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; // 从"index+1"开始,用后面的元素替换前面的元素。 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); // 将最后一个元素设为null elementData[--size] = null; // Let gc do its work }
remove方法首先查找要删除对象的index,然后调用fastRemove方法将index后边的对象往前复制一位,并将数组中的最后一位元素设置为null,释放对象的引用。
这里有个小知识点:为什么要分开讨论null的情况呢?
因为查找时候用的比较方法<equals()>是比较的对象的值。
完结撒花~这篇博客是用健康写成的。外面下着雨,只穿着短袖,在图书馆发抖。
参考文章链接:https://blog.csdn.net/u013309870/article/details/72519272