ArrayList源码分析超详细(转载)

ArrayList源码分析超详细

 

ArrayList源码分析超详解

想要分析下源码是件好事,但是如何去进行分析呢?以我的例子来说,我进行源码分析的过程如下几步:

  • 找到类:利用 IDEA 找到所需要分析的类(ztrl+N查找ArraList)(此处就是 ArrayList)
  • 新建类:新建一个类,命名为 ArrayList,将源码拷贝到该类。因为我们分析的时候肯定是需要进行代码注释,以及调试的,而jdk的源码,我们是没法在里面直接进行代码注释和断点调试的
  • 按照上面的方法将新建AbstractList类,并将源码拷贝过来,这是由于ArrayList中要用到AbstractList类中的变量,如果不拷贝过来就会报错。
  • 修改类:我们刚拷贝过来的源码,肯定会报错的。报错原因比如:包名不匹配、继承的类中权限问题,因此我们需要对源码进行修改。
  • 查看代码 + 测试案例 + 断点调试:前面准备好了,就到分析的过程了。分析,不仅仅是简单的看下代码,我们需要仔细思考,且辅以相应的测试案例,甚至于进行断点跟踪查看运行过程。

好了,我们获得了ArrayList源码后该怎样做?当然是一步步分析,这里我使用的是jdk 1.8的包含一些1.8新特性的源码,往下看,看完可能需要你花费很久的时间.

package annoction;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator; import sun.misc.SharedSecrets; public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { /** * 序列号 */ private static final long serialVersionUID = 8683452581122892189L; /** * 默认容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 一个空数组 * 当用户指定该 ArrayList 容量为 0 时,返回该空数组 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 一个空数组实例 * - 当用户没有指定 ArrayList 的容量时(即调用无参构造函数),返回的是该数组==>刚创建一个 ArrayList 时,其内数据量为 0。 * - 当用户第一次添加元素时,该数组将会扩容,变成默认容量为 10(DEFAULT_CAPACITY) 的一个数组===>通过 ensureCapacityInternal() 实现 * 它与 EMPTY_ELEMENTDATA 的区别就是:该数组是默认返回的,而后者是在用户指定容量为 0 时返回 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * ArrayList基于数组实现,用该数组保存数据, ArrayList 的容量就是该数组的长度 * - 该值为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,当第一次添加元素进入 ArrayList 中时,数组将扩容值 DEFAULT_CAPACITY(10) */ transient Object[] elementData; // non-private to simplify nested class access /** * ArrayList实际存储的数据数量 */ private int size; /** * 创建一个初试容量的、空的ArrayList * @param initialCapacity 初始容量 * @throws IllegalArgumentException 当初试容量值非法(小于0)时抛出 */ 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,此时其内数组缓冲区 elementData = {}, 长度为 0 * - 当元素第一次被加入时,扩容至默认容量 10 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * 创建一个包含collection的ArrayList * @param c 要放入 ArrayList 中的集合,其内元素将会全部添加到新建的 ArrayList 实例中 * @throws NullPointerException 当参数 c 为 null 时抛出异常 */ public ArrayList(Collection<? extends E> c) { //将集合转化成Object[]数组 elementData = c.toArray(); //把转化后的Object[]数组长度赋值给当前ArrayList的size,并判断是否为0 if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) // 这句话意思是:c.toArray 可能不会返回 Object[],可以查看 java 官方编号为 6260652 的 bug if (elementData.getClass() != Object[].class) // 若 c.toArray() 返回的数组类型不是 Object[],则利用 Arrays.copyOf(); 来构造一个大小为 size 的 Object[] 数组 elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 替换空数组 this.elementData = EMPTY_ELEMENTDATA; } } /** * 将数组缓冲区大小调整到实际 ArrayList 存储元素的大小,即 elementData = Arrays.copyOf(elementData, size); * - 该方法由用户手动调用,以减少空间资源浪费的目的 ce. */ public void trimToSize() { // modCount 是 AbstractList 的属性值:protected transient int modCount = 0; // [问] modCount 有什么用? modCount++; // 当实际大小 < 数组缓冲区大小时 // 如调用默认构造函数后,刚添加一个元素,此时 elementData.length = 10,而 size = 1 // 通过这一步,可以使得空间得到有效利用,而不会出现资源浪费的情况 if (size < elementData.length) { // 注意这里:这里的执行顺序不是 (elementData = (size == 0) ) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); // 而是:elementData = ((size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size)); // 这里是运算符优先级的语法 // 调整数组缓冲区 elementData,变为实际存储大小 Arrays.copyOf(elementData, size) //先判断size是否为0,如果为0:实际存储为EMPTY_ELEMENTDATA,如果有数据就是Arrays.copyOf(elementData, size) elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } } /** * 指定 ArrayList 的容量 * @param minCapacity 指定的最小容量 */ public void ensureCapacity(int minCapacity) { // 最小扩充容量,默认是 10 //这句就是:判断是不是空的ArrayList,如果是的最小扩充容量10,否则最小扩充量为0 //上面无参构造函数创建后,当元素第一次被加入时,扩容至默认容量 10,就是靠这句代码 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; // 若用户指定的最小容量 > 最小扩充容量,则以用户指定的为准,否则还是 10 if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } } /** * 私有方法:明确 ArrayList 的容量,提供给本类使用的方法 * - 用于内部优化,保证空间资源不被浪费:尤其在 add() 方法添加时起效 * @param minCapacity 指定的最小容量 */ private void ensureCapacityInternal(int minCapacity) { // 若 elementData == {},则取 minCapacity 为 默认容量和参数 minCapacity 之间的最大值 // 注:ensureCapacity() 是提供给用户使用的方法,在 ArrayList 的实现中并没有使用 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity= Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } /** * 私有方法:明确 ArrayList 的容量 * - 用于内部优化,保证空间资源不被浪费:尤其在 add() 方法添加时起效 * @param minCapacity 指定的最小容量 */ private void ensureExplicitCapacity(int minCapacity) { // 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的 modCount++; // 防止溢出代码:确保指定的最小容量 > 数组缓冲区当前的长度 // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * 数组缓冲区最大存储容量 * - 一些 VM 会在一个数组中存储某些数据--->为什么要减去 8 的原因 * - 尝试分配这个最大存储容量,可能会导致 OutOfMemoryError(当该值 > VM 的限制时) */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 私有方法:扩容,以确保 ArrayList 至少能存储 minCapacity 个元素 * - 扩容计算:newCapacity = oldCapacity + (oldCapacity >> 1); 扩充当前容量的1.5倍 * @param minCapacity 指定的最小容量 */ private void grow(int minCapacity) { // 防止溢出代码 int oldCapacity = elementData.length; // 运算符 >> 是带符号右移. 如 oldCapacity = 10,则 newCapacity = 10 + (10 >> 1) = 10 + 5 = 15 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) // 若 newCapacity 依旧小于 minCapacity newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) // 若 newCapacity 大于最大存储容量,则进行大容量分配 newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } /** * 私有方法:大容量分配,最大分配 Integer.MAX_VALUE * @param minCapacity */ private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** * 返回ArrayList实际存储的元素数量 */ public int size() { return size; } /** * ArrayList是否有元素 */ public boolean isEmpty() { return size == 0; } /** * 是否包含o元素 */ public boolean contains(Object o) { // 根据 indexOf() 的值(索引值)来判断,大于等于 0 就包含 // 注意:等于 0 的情况不能漏,因为索引号是从 0 开始计数的 return indexOf(o) >= 0; } /** * 顺序查找,返回元素的最低索引值(最首先出现的索引位置) * @return 存在?最低索引值:-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; } /** * 逆序查找,返回元素的最低索引值(最首先出现的索引位置) * 

转载于:https://www.cnblogs.com/lixinjun8080/p/10918889.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值