博客
关于我
阅读源码,从ArrayList开始
阅读量:475 次
发布时间:2019-03-06

本文共 3705 字,大约阅读时间需要 12 分钟。

阅读源码是一项非常有价值的技能,它不仅能帮助我们更好地理解代码的运行机制,还能为我们的编程能力提供宝贵的提升。今天,我们以ArrayList为例,来探讨一下它的源码结构以及背后的逻辑。

类签名

ArrayList是一个非常常用的Java集合,它的类签名为:

public class ArrayList
extends AbstractList
implements List
, RandomAccess, Cloneable, java.io.Serializable

从类签名可以看出,ArrayList继承自AbstractList,并实现了List、RandomAccess、Cloneable以及序列化接口。这些接口赋予了ArrayList丰富的功能,例如支持随机访问、克隆操作以及序列化。

变量

ArrayList内部维护了一些关键变量来管理数据:

// 序列化版本号private static final long serialVersionUID = 8683452581122892189L;// 常量,默认容量为10private static final int DEFAULT_CAPACITY = 10;// 常量,初始化一个空的Object数组private static final Object[] EMPTY_ELEMENTDATA = {};// 常量,初始化一个空的Object数组,与EMPTY_ELEMENTDATA用于区别初始化时指定容量0还是默认不指定private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};// 变量,真正用来存储元素的数组名transient Object[] elementData;// 数组中实际存储的元素数量,未初始化则默认为0private int size;

这些变量中,EMPTY_ELEMENTDATADEFAULTCAPACITY_EMPTY_ELEMENTDATA的区别在于它们用于不同的初始化场景。例如,当使用new ArrayList(0)时,会使用EMPTY_ELEMENTDATA;而使用new ArrayList()new ArrayList(10)时,则会使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA

构造方法

ArrayList提供了多个构造方法来满足不同场景的需求:

// 不指定初始容量的构造函数public ArrayList() {    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}// 指定初始容量的构造函数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);    }}// 通过已有集合直接构造public ArrayList(Collection
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; }}

这些构造方法的主要区别在于它们如何初始化elementData数组。通过选择不同的构造方法,可以优化ArrayList的初始化性能和内存使用。

常用方法

ArrayList的常用方法包括addremovecontains等。以add方法为例:

public boolean add(E e) {    ensureCapacityInternal(size + 1);    elementData[size++] = e;    return true;}

在添加元素之前,add方法会检查当前数组的容量是否足够。如果不够,则会调用ensureCapacityInternal方法进行扩容。

检查容量:ensureCapacityInternal

private void ensureCapacityInternal(int minCapacity) {    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private static int calculateCapacity(Object[] elementData, int minCapacity) {    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {        return Math.max(DEFAULT_CAPACITY, minCapacity);    }    return minCapacity;}private void ensureExplicitCapacity(int minCapacity) {    modCount++;    if (minCapacity - elementData.length > 0) {        grow(minCapacity);    }}

ensureCapacityInternal方法首先通过calculateCapacity计算所需的最小容量,然后调用ensureExplicitCapacity进行扩容操作。扩容时会调用grow方法来增加数组的大小。

扩容方法:grow

private void grow(int minCapacity) {    int oldCapacity = elementData.length;    int newCapacity = oldCapacity + (oldCapacity > 1 ? oldCapacity / 2 : oldCapacity);    if (newCapacity - minCapacity < 0) {        newCapacity = minCapacity;    }    if (newCapacity - MAX_ARRAY_SIZE > 0) {        newCapacity = hugeCapacity(minCapacity);    }    elementData = Arrays.copyOf(elementData, newCapacity);}

grow方法根据当前数组的大小和所需容量,决定如何扩展数组。它会尽量增加数组大小,但不会超过MAX_ARRAY_SIZEInteger.MAX_VALUE

回到开始的问题

在创建ArrayList时:

  • 不指定初始容量:

    List list1 = new ArrayList();

    这将使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA来初始化数组。第一次添加元素时,数组会扩容到默认容量10。

  • 指定初始容量为0:

    List list2 = new ArrayList(0);

    这将使用EMPTY_ELEMENTDATA来初始化数组。第一次添加元素时,数组会扩容到1。

  • 指定初始容量为10:

    List list4 = new ArrayList(10);

    这将直接创建一个容量为10的数组,无需扩容。

通过选择合适的构造方法,可以避免不必要的扩容操作,从而提高性能。

小结

通过对ArrayList源码的分析,我们可以更深入地理解其内部工作机制。阅读源码不仅能帮助我们掌握专业技能,还能让我们意识到代码背后的设计理念和优化思路。建议在阅读源码时,从类签名开始,逐步深入了解变量、构造方法和常用方法。同时,注意观察代码中的设计模式和算法,这将有助于我们在实际编程中做出更好的决策。

转载地址:http://efpbz.baihongyu.com/

你可能感兴趣的文章
Objective-C实现余弦cosx函数(附完整源码)
查看>>
Objective-C实现余数定理算法(附完整源码)
查看>>
Objective-C实现使用 2 个堆栈形成队列算法(附完整源码)
查看>>
Objective-C实现使用 radix-2 快速傅里叶变换的快速多项式乘法算法(附完整源码)
查看>>
Objective-C实现使用 ziggurat() 作为 OpenMP 并行程序中的随机数生成器 (RNG)(附完整源码)
查看>>
Objective-C实现使用DisjointSet 检测无向循环算法(附完整源码)
查看>>
Objective-C实现使用Prim算法确定图的最小生成树算法(附完整源码)
查看>>
Objective-C实现使用二元运算符将两个数字相加fullAdder算法(附完整源码)
查看>>
Objective-C实现使用分而治之找到单峰列表的峰值算法(附完整源码)
查看>>
Objective-C实现使用数组实现约瑟夫环(附完整源码)
查看>>
Objective-C实现使用欧几里得除法的 a/b 的十进制扩展算法(附完整源码)
查看>>
Objective-C实现使用矩阵求幂的第 n 个斐波那契算法(附完整源码)
查看>>
Objective-C实现使用管道重定向进程输入输出(附完整源码)
查看>>
Objective-C实现倒计时(附完整源码)
查看>>
Objective-C实现借记款项功能(附完整源码)
查看>>
Objective-C实现全年3天打渔,2天晒网(附完整源码)
查看>>
Objective-C实现八进制转十进制算法(附完整源码)
查看>>
Objective-C实现共享内存(附完整源码)
查看>>
Objective-C实现关机、重启、注销功能的实现(附完整源代码)
查看>>
Objective-C实现关机程序(附完整源码)
查看>>