JDK1.7源码笔记之ArrayList类
来源:互联网 发布:人工智能科技园 编辑:程序博客网 时间:2024/05/03 18:45
1. class 简介
ArrayList是Java集合家族中最常用的容器,本质上是一个长度可变的array,它提供了一系列操作数组的方法,增加元素、删除元素、修改元素、根据索引取元素、迭代、扩容、取子列表、转换成数组等方法。使用ArrayList要注意尽量减少自动扩容的次数,以降低性能开销。
2. class内部原理及特点
- 不是线程安全的,没有Synchronized关键字。
- 允许向其中添加null。
- 内部是一个数组Object[] elementData,因为设计者设计java集合时还没有引进泛型概念。数组的优势在于快速检索,所以其按索引取值、修改和尾部添加等操作有优势,尽量不要进行插入和删除操作。
- 可以指定ArrayList的初始容量,默认为10,当内部数组已满,则当前总容量X1.5扩容,扩容时新建一个数组,将旧数组内容使用System.arraycopy复制到新数组。可以预估数据的数量,以减少频繁扩容带来的开销。.
- 其迭代器是快速失败的(java.util下的集合都是),在一个ArrayList的迭代器创建之后调用非迭代器中的方法对ArrayList的内部结构进行修改都会抛出ConcurrentModificationException。
3. class源码细节分析
对数组进行增删改查的操作在学习数据结构的时候已经非常熟悉了,没必要浪费时间,这里先看其它容易被忽视的核心方法。
ensureCapacity, ensureCapacityInternal和grow
/* 负数容量无视 */public void ensureCapacity(int minCapacity) {if (minCapacity > 0) ensureCapacityInternal(minCapacity);}/* ArrayList的内部数组只能扩大不能缩小 */private void ensureCapacityInternal(int minCapacity) { modCount++;//记录修改的次数,用于在迭代器迭代过程中检测是否有其它线程对容器进行了修改。 if (minCapacity - elementData.length > 0) grow(minCapacity);}/* 1.5倍扩容,如果还不够则直接等于所需容量 */private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//X1.5倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0)//超过最大限制 newCapacity = hugeCapacity(minCapacity);//则等于最大值 //新创建一个数组,把内容copy到新数组中 elementData = Arrays.copyOf(elementData, newCapacity);}
batchRemove, removeAll和retainAll
public boolean removeAll(Collection<?> c) { return batchRemove(c, false);}public boolean retainAll(Collection<?> c) { return batchRemove(c, true);}/* 移除和保留是相反的操作,complement表示是否进行相反操作 */private boolean batchRemove(Collection<?> c, boolean complement){ final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++)//包含这个元素则选择覆盖或跳过 if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } return modified;}
subList
/* 返回ArrayList某个部分的视图(一个子列表),其拥有ArrayList所有的方法,对SubList进行任何操作都会反映到本体ArrayList中,对其产生相同的影响 */public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex);}
iterator
public Iterator<E> iterator() { return new Itr();}private class Itr implements Iterator<E> { int cursor; //初始为0,指向下一个元素 int lastRet = -1; //指向上一次的元素,没有则为-1 int expectedModCount = modCount;//用于在迭代过程中和容器的modeCount进行比较,检测是否有别的线程修改了容器。 public boolean hasNext() {//是否还有元素 return cursor != size; } @SuppressWarnings("unchecked") 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() {//移除上一次的元素,所以如果要用迭代器删除list的第一个元素,必须先调用一次next() if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }}//实现了List接口的集合容器还有一个listIterator方法,其返回的迭代器可以前后迭代。
ArrayList以及其它非Map集合的终极父类Collection实现了Iterable接口,可以在foreach语句中遍历集合for(Object o : collection){}
,实际上是使用了迭代器。
//Implementing this interface allows an object to be the target of the "foreach" statement.//@param <T> the type of elements returned by the iterator * * @since 1.5 */public interface Iterable<T> { /** * Returns an iterator over a set of elements of type T. * * @return an Iterator. */ Iterator<T> iterator();}
4. 总结
ArrayList是最常用的java集合,由于在集合被加入JDK之前还没有泛型,在源码中经常可以看到Object类型。使用ArrayList要尽量减少其扩容的次数,尽量不要对其进行插入和删除的操作,在需要的时候手动扩容。
1 0
- JDK1.7源码笔记之ArrayList类
- JDK1.7源码笔记之Arrays类
- JDK1.7源码笔记之String类
- JDK1.7源码笔记之LinkedList类
- JDK1.7源码笔记之ArrayDeque类
- jdk1.7之ArrayList
- [JDK1.7源码阅读]ArrayList
- JDK1.7源码笔记之StringBuilder和StringBuffer类
- ArrayList 源码解析 及其扩展(jdk1.7)
- ArrayList源码解析(基于JDK1.7)
- (7) java源码分析------之ArrayList (对应数据结构中线性表中的顺序表,JDK1.6)
- 【Java集合框架源码分析(JDK1.7)】-ArrayList源码分析
- jdk1.6之ArrayList
- ArrayList源码分析(jdk1.8)
- ArrayList源码解析(jdk1.8)
- ArrayList源码分析 JDK1.8
- jdk1.8----ArrayList源码解析
- jdk1.8 ArrayList源码详解
- LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- CodeForces 627 A.XOR Equation(位运算)
- Mybatis 一对多 查询
- iOS 集合的深拷贝与浅拷贝
- 历届试题 连号区间数 (蓝桥杯)
- JDK1.7源码笔记之ArrayList类
- 输入一个日期,判断该年是否是闰年,该月处于什么季节,该月有多少天。
- plist文件的读写
- XDOJ 1208 B.笑爷买房 【DFS】
- 屏幕适配
- git错误
- leetcode-547. Friend Circles
- 算法训练 排列问题
- 建立一个类Prime,用来判断某整数是否为素数。具体要求如下: