今天介绍常常使用的一个Java集合类——ArrayList(基于JDK1.8.0_121)。ArrayList在工做和平常面试中常常被使用或者提到。总的来讲,工做中使用ArrayList主要是由于动态数组的方便性,面试中出现ArrayList常常是和LinkedList/Vector一块儿出现,分析这三种集合的异同。java
图片是直接从IntelliJ中导出来的,其中:蓝色线条意味着继承,绿色线条意味着接口实现。面试
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
咱们首先须要明白而且牢记在心里的是,ArrayList本质上是一个数组,可是与Java中基础的数组所不一样的是,它可以动态增加本身的容量。
经过ArrayList的定义,能够知道ArrayList继承了AbstractList,同时实现了List,RandomAccess,Cloneable和java.io.Serializable接口。数组
继承了AbstractList类,实现了List,意味着ArrayList是一个数组队列,提供了诸如增删改查、遍历等功能。
实现了RandomAccess接口,意味着ArrayList提供了随机访问的功能。RandomAccess接口在Java中是用来被List实现,用来提供快速访问功能的。在ArrayList中,即咱们能够经过元素的序号快速获取元素对象。
实现了Cloneable接口,意味着ArrayList实现了clone()函数,能被克隆。
实现了java.io.Serializable接口,意味着ArrayList可以经过序列化进行传输。dom
private static final int DEFAULT_CAPACITY = 10; transient Object[] elementData; private int size;
(1)ArrayList的默认容量为10;
(2)elementData是"Object类型的数组",全部ArrayList元素都保存在elementData中。在ArrayList中,elementData是一个动态数组。须要注意的是,ArrayList经过构造函数ArrayList(int initialCapacity)定义初始量initialCapacity;
(3)size是动态数组的实际大小。函数
//ArrayList带容量的构造函数 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //新建一个容量为initialCapacity的数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } //ArrayList默认构造函数,默认为空 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 构造一个包含指定元素的list public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { this.elementData = EMPTY_ELEMENTDATA; } }
第一个构造方法使用提供的initialCapacity来初始化elementData数组的大小。
第二个构造方法默认数组为0。
第三个构造方法则将提供的集合转成数组返回给elementData(返回若不是Object[]将调用Arrays.copyOf方法将其转为Object[])。this
public boolean add(E e) { //扩容判断 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public void add(int index, E element) { //判断index是否越界,错误产生IndexOutOfBoundsException rangeCheckForAdd(index); //进行扩容检查 ensureCapacityInternal(size + 1); // Increments modCount!! //对数组进行复制,将空出的Index位置出入element,并将index后的全部数据后移一个位置。 System.arraycopy(elementData, index, elementData, index + 1, size - index); //将index上的数据设置为element elementData[index] = element; //容量+1 size++; }
public E remove(int index) { //边界检查 rangeCheck(index); modCount++; //oldValue即要删除的元素 E oldValue = elementData(index); //要复制的元素 int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //释放最后一个元素 elementData[--size] = null; // clear to let GC do its work return oldValue; } public boolean remove(Object o) { //对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; }
public E set(int index, E element) { //数组扩容 rangeCheck(index); //获取要更新的位置的数据 E oldValue = elementData(index); //更新元素 elementData[index] = element; return oldValue; }
newCapacity = oldCapacity + (oldCapacity >> 1)