Java源码阅读之ArrayList
来源:互联网 发布:mix2 知乎 编辑:程序博客网 时间:2024/05/22 03:03
Java源码阅读之ArrayList
前言:网上有很多关于java源代码的文章,其中不乏逐行分析代码的大牛博文。本文不再赘述每行代码的意思,而是分析一些常用方法的代码段。这样,我们在编程的时候,就能了解函数背后运行的机制,使得我们程序设计得更为合理。
1、知识汇总
ArrayList的核心是:
transient Object[] elementData;
所有的操作都围绕这个数组进行,因此我们说ArrayList本质上就是一个数组。带着这个思路,理解ArrayList就很容易了。
ArrayList是一个很厉害的数组,它能够动态申请内存。当存储空间不够时,会自动扩容。由于底层是用数组实现的,所以ArrayList的查询快,插入删除慢。同时扩容操作会复制数组中的元素,所以扩容也很耗时。
因此在程序设计时,使用ArrayList前,我们最好知道数组的大小,避免多次扩容。另外,如果程序需要大量的插入和删除操作,建议使用LinkedList。
2、构造方法
构造方法被重载为以下三个:
public ArrayList() {} // 无参构造方法public ArrayList(int initialCapacity){} // 一个参数,表示初始化容量大小public ArrayList(Collection<? extends E> c) {} // 通过集合构造ArrayList
三个方法的源码分别如下:
/** * 无参构造方法,数组的初始容量设置为10 */public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/** * 通过设置初始容量构造ArrayList */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); }}/** * 通过集合构造ArrayList */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; }}
3、扩容
当ArrayList的空间不够用时,会自动申请内存,叫做扩容。扩容的核心部分如下:
/** * minCapacity:当前需要的容量是minCapacity,扩容后的容量应当大于等于minCapacity */private void grow(int minCapacity) { int oldCapacity = elementData.length; // 扩容前的容量 int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量等于扩容前容量的1.5倍 // 如果新容量还不够用,那么就扩容到minCapacity得了 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // 如果新容量超过ArrayList最大容量,那么就用最大容量了(ArrayList的容量总得有个上限吧) // 插一句:最大容量为:0x7fffffff-8 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 扩容的核心就是这句话,将旧数组里的内容复制到新数组里 // 这个操作很耗时,因此我们应当尽量减少扩容 elementData = Arrays.copyOf(elementData, newCapacity);}
4、插入
向ArrayList中插入元素时,分为在末尾插入和在指定位置插入。插入前需要扩容,在指定位置插入时,还要将数组元素依次向后移动一位,因此在指定位置插入比较耗时。
/** * 在ArrayList末尾添加元素 */public boolean add(E e) { ensureCapacityInternal(size + 1); // 添加元素需要扩容 elementData[size++] = e; // 为数组最后一位赋值 return true;}/** * 在指定位置插入元素 */public void add(int index, E element) { rangeCheckForAdd(index); // 检查插入位置是否在[0, size]之间,size是ArrayList的长度 ensureCapacityInternal(size + 1); // 扩容 System.arraycopy(elementData, index, elementData, index + 1, size - index); // 复制元素,依次向后串一位 elementData[index] = element; // 给插入位置的元素重新赋值 size++;}
5、删除
在删除指定的元素时,需要将删除位置后面的元素依次向前移动一位,这个操作是耗时的,因此在ArrayList里执行删除是不划算的。除非我们只删除最后一位元素。
/** * 删除指定的元素 */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;}/* * 删除指定位置的元素 */private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) // 把要删除的位置后面的元素,依次向前移动一位,然后删除最后一位 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // 最后一位设置为null,等待GC}/** * 删除所有元素 */public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0;}
6、修改
修改就是元素重新赋值
/** * 重新为指定元素设置值 */public E set(int index, E element) { rangeCheck(index); // 范围检查 E oldValue = elementData(index); // 该位置的原始值 elementData[index] = element; // 在指定位置赋值 return oldValue; // 返回原始值}
7、查询
查询某个元素,其核心是一层for循环遍历,时间复杂度O(n)
public boolean contains(Object o) { return indexOf(o) >= 0;}/** * 返回元素第一次出现的位置,如果不存在则返回-1 */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;}
除了上述方法外,还有addAll()、ArrayList()、isEmpty()等方法,这里不再赘述,如果想查看详细的分析,可以参考:
http://blog.csdn.net/ns_code/article/details/35568011
今天就到这里,拜拜~
- Java源码阅读之ArrayList
- Java源码阅读之ArrayList
- Java源码阅读之ArrayList
- 源码阅读之ArrayList
- Java源码阅读-ArrayList
- Java源码阅读-ArrayList
- JDK源码阅读之ArrayList
- jdk源码阅读之ArrayList
- java数据结构 ArrayList源码阅读
- java源码阅读系列-ArrayList
- 源码面前,原形毕露之ArrayList源码阅读
- Java源码之ArrayList
- JAVA源码之ArrayList
- java源码之Arraylist
- Java源码之ArrayList
- Java源码之ArrayList(二)
- java源码分析之ArrayList
- Java 源码解析之 ArrayList
- 主席树(hdu2665)
- 数论学习(题库有很多啦。)
- 51nod 1242 斐波那契数列第N项
- 树链剖分基础模板(BZOJ1036[ZJOI2008]树的统计Count)
- 树链剖分模板题(luogu3384 【模板】树链剖分)
- Java源码阅读之ArrayList
- 建图最短路同余(luogu2662 vijos1054 xjoi2157)(bzoj2118)
- 左偏树
- 欧拉函数性质证明 : n所有约数的欧拉函数和等于n
- 冒泡排序法(Bubble Sorting)
- contest 15
- 为什么要来写博客
- 计算几何基础模板 以后还会更新
- 判断直线相交思维好题 (poj1039)