正文
ArrayList是一个集合,继承了AbstractList类,实现了List接口,有如下特点:
1. Object数组保存元素
2. 数组长度可自动增加,每次不够用时才扩容,新容量 = 旧容量 * 1.5
3. 使用迭代器进行遍历时,不能修改ArrayList的结构(增删),否则报错
4. subList方法返回的是ArrayList的子类,和旧集合共用同一个数组
5. 线程不安全
6. 底层数据结构是数组,查询快,增删慢
7. 元素可以重复,可以为null
相关源码解释:
这东西其实很简单的
注意:这并不是全部源码,我只是抽了部分我认为关键的
public class ArrayListextends AbstractList implements List , RandomAccess, Cloneable, java.io.Serializable{ /** 默认初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** 存放元素的数组 */ transient Object[] elementData; /** 元素个数 */ private int size; /** 指定默认容量时的空数组,我们创建ArrayList时如果指定了初始大小,那空数组就用这个 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** 默认容量的空数组,我们创建ArrayList时不传入初始大小,那空数组就用这个 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * ArrayList的数组结构改变次数,如果我们用迭代器进行遍历数组时,直接给ArrayList添加或删除元素,就会因为这玩意而抛异常 。 * 只有结构改变,添加或删除,才会修改这个值 * * */ protected transient int modCount = 0; // 这个属性是AbstractList的 /** 指定的数组元素最大数量 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 给定初始化数组大小 * */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * 没有指定数组大小,这样子我们添加元素是,就要扩容了,所以为了提高效率,最好创建时就指定大小 * 我记得以前是直接创建默认大小的数组,可能是jdk1.8改了吧 * */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /*** * 构造函数传个集合进来 * */ public ArrayList(Collection extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } } /** * 扩容方法 * @param minCapacity 我们需要的最小的容量 * */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; /** 新容量 = 旧容量 * 1.5 */ int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) /** 如果 旧容量 * 1.5还不够你的要求,那就按你要求的来 */ newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) /** 如果你要求的大小比我指定的数组最大容量还大,那就扩大到Integer.MAX_VALUE,这是我ArrayList的最大容量了 */ newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } /** * 获取元素个数 * */ public int size() { return size; } /** * 判断是否为空 * */ public boolean isEmpty() { return size == 0; } /** * 是否包含某个元素 * */ public boolean contains(Object o) { return indexOf(o) >= 0; } /** * 别人其实也是用循环判断的,所以一点也不神秘。 * 另外比较相等使用equals来比较的,Object的equals方法是比较地址 * 所以如果你有特殊要求,记得要重写equals方法 * */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; } /** * 不要随便用他的克隆方法,因为在克隆元素时,不会调用元素的clone方法的。 * 他是直接用System.arraycopy()这个方法进行内存复制的,所以浅拷贝的后果,你懂得。 * 只要不涉及修改元素的内容,其他你随意。 * */ public Object clone() { try { ArrayList> v = (ArrayList>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } } /** * 这个方法返回的数组,也是会影响原数组的,也是用System.arraycopy()这个方法进行内存复制的。 * 只要不涉及修改元素的内容,其他你随意。 * */ public Object[] toArray() { return Arrays.copyOf(elementData, size); } /** * 获取元素 * */ public E get(int index) { rangeCheck(index); return elementData(index); } /** * 修改元素 * */ public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } /** * 添加元素 * */ public boolean add(E e) { /** 还记得前面说过modCount这个属性么 */ /** 不够容量就自动扩容 */ ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } /** * 删除元素 * */ public E remove(int index) { rangeCheck(index); /** modCount又出现了 */ modCount++; 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 void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } /*** * 迭代器,很重要、很重要、很重要 * */ private class Itr implements Iterator { int cursor; // 下一个返回的元素下标 int lastRet = -1; // 上一个返回的元素下标,-1表示没有 /** 看到这玩意了没,初始化时就是ArrayList的最新值 */ int expectedModCount = modCount; /** * 判断是否还有下一个元素 * */ public boolean hasNext() { return cursor != size; } /** * 记住这个异常,新人经常会碰到的。 * 这里会检查ArrayList的modCount和迭代器的expectedModCount这玩意是否相等。 * 如果你是直接操作ArrayList来改变数组结构的,那么这两个值就不等了,那就肯定报错。 * 如果你是通过迭代器来改变ArrayList的数组结构的,那么就没问题,因为迭代器会顺便把自己的expectedModCount也改一下。 * */ final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } /** * 获取下一个元素 * */ public E next() { /** 直接就是先检查下你有没有调皮,要是你直接改了数组,那就报错了 */ checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } /** * 删除当前元素 * */ public void remove() { if (lastRet < 0) throw new IllegalStateException(); /** 还是先检查下你有没有调皮,要是你直接改了数组,那就报错了 */ checkForComodification(); try { /** 直接用ArrayList的方法来删除元素的 */ ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; /** 注意看这里,迭代器改了,他会自己同步一下,不像你直接改了,还不搽屁股 */ expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } } /** * 截取数组的一部分。 * 这里一定要记住,返回的不是ArrayList类型的对象。 * 这里一定要记住,返回的不是ArrayList类型的对象。 * 这里一定要记住,返回的不是ArrayList类型的对象。 * */ public List subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); } /** * 子List类,SubList用的是ArrayList的数组,只是设置了上下限而已。 * 如果你修改了SubList,原ArrayList也会一起变。 * */ private class SubList extends AbstractList implements RandomAccess { /* SubList用的是ArrayList的数组,只是 */ private final AbstractList parent; private final int parentOffset; private final int offset; int size; SubList(AbstractList parent, int offset, int fromIndex, int toIndex) { this.parent = parent; this.parentOffset = fromIndex; this.offset = offset + fromIndex; this.size = toIndex - fromIndex; this.modCount = ArrayList.this.modCount; } public E set(int index, E e) { rangeCheck(index); checkForComodification(); E oldValue = ArrayList.this.elementData(offset + index); ArrayList.this.elementData[offset + index] = e; return oldValue; } public E get(int index) { rangeCheck(index); checkForComodification(); return ArrayList.this.elementData(offset + index); } public int size() { checkForComodification(); return this.size; } public void add(int index, E e) { rangeCheckForAdd(index); checkForComodification(); parent.add(parentOffset + index, e); this.modCount = parent.modCount; this.size++; } } }