一步一步解析集合框架ArrayList源码

我在阅读源码的过程中很多时候是没有头绪的。所以为了避免大家也遇到这种状况,源码不求全求大,做到“透过实践看源码”,分块分层。
首先对ArrayList做个总体介绍:

ArrayList的底层存储结构是数组,实际上在这个类中真正保存数据的是内部定义的一个数组,自身的数据操作只是封装了数组的操作!

  • 首先看定义:
//创建ArrayList对象;<String>泛型,表明list将来保存的是String
ArrayList<String> list=new ArrayList<String>();

创建实例首先看内部变量

 /**
     * 默认的集合容量:10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空的数组实例(共享),用来在指定容量为0时初始化。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 空的数组实例(共享)。在默认的构造函数中初始化
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 底层结构,数组
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * 集合大小,指的是集合内包含的元素个数
     */
    private int size;

然后调用默认构造函数

/**
 * 默认的构造函数;Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

至此就完成了实例化操作,此时ArrayList对象list,内部elementData 指向了一个Object[0]数组,size默认值为0。

随后的操作均是对数组elementData 进行操作。

  • 添加数据
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<String>();
        list.add("first");
        list.add("second");
    }

源码分析

//添加数据
 public boolean add(E e) {
        //扩充集合容量,防止溢出,直至添加第10个数据时都不会再扩充容量,避免频繁扩充容量导致性能下降
        ensureCapacityInternal(size + 1); 
        //添加数据
        elementData[size++] = e;
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        //使用默认构造函数实例化,第一次添加数据minCapacity=10
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //比较DEFAULT_CAPACITY, minCapacity的最大值,赋值给minCapacity
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 如果minCapacity较大,扩充容量
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 集合的最大容量
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 扩充容量
     */
    private void grow(int minCapacity) {
        // 原来的集合容量
        int oldCapacity = elementData.length;
        //>>1相当于除于2取整,构建新容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //复制一个新的数组,容量为newCapacity,内容为elementData,多余的用默认值填充,如null,0;
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
  • 获取元素
public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<String>();
        list.add("first");
        list.add("second");
        //第一个元素值
        String ele1=list.get(0);
        System.out.println(ele1);
        //第二个元素值
        String ele2=list.get(1);
        System.out.println(ele2);
    }

输出结果: first
second

源码分析

    /**
     * 返回索引元素
     */
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }
    /**
     * 检查索引是否超出范围,超出就报异常
     */
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    // 根据索引获取元素。底层是数组。
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

至此ArrayList类的基本 添加数据,获取数据 的源码解析完毕!
继续阅读……
如有错误,欢迎指正!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值