当前位置:主页 > android教程 > Java ArrayList

Java ArrayList源码深入分析

发布:2023-03-03 16:00:02 59


本站精选了一篇相关的编程文章,网友浦鸿博根据主题投稿了本篇教程内容,涉及到Java、ArrayList、Java、ArrayList源码、Java ArrayList相关内容,已被627网友关注,涉猎到的知识点内容可以在下方电子书获得。

Java ArrayList

1.ArrayList 是基数组结构的,需要连续的内存空间

从构造函数可以看出,ArrayList内部用一个Object数组来保存数据。

对于无参构造,ArrayList会创建一个大小为10的初始数组,第一次扩容时会创建默认大小数组。

 //无参构造函数,会构造一个空数组。第一次扩容时会创默认大小为10的数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    transient Object[] elementData;
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    private static final Object[] 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);
        }
    }

2.对于set和get方法ArrayList效率高,因为可以直接通过下标获取存储对象。

 //直接通过角标从数组中取出元素
    public E get(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        return (E) elementData[index];
    }
    //set 方法,直接通过index 拿到元素,进行修改就行。
    public E set(int index, E element) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        E oldValue = (E) elementData[index];
        elementData[index] = element;
        return oldValue;
    }

3.对于add方法,有两种情况:

第一种是在尾部添加,不需要移动数组。

//Add 方法 ,在末端插入不需要
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

第二种情况在指定位置添加或插入数据,则需要移动数组,效率比较低。如果插入在第0个位置则需要移动整个数组。

  public void add(int index, E element) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //被插入的元素在index。则移动的数组应该从index开始,向后移动一个,
		//移动的数组长度 size-index 从index开始的数组长度
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        elementData[index] = element;
        size++;
    }

在add时还需要考虑到数组的扩容问题,看ensureCapacityInternal方法

 private void ensureCapacityInternal(int minCapacity) {
        //通过无参构造创建为设置初始大小时,判断条件为true
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //创建默认大小的数组,初始大小是10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

添加元素后,元素数量大于数组长度时,进行扩容grow,扩容大小是原数组的1.5倍

 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        //新增后,数组容量已经大于了数组长度,则进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
		//新的数组大小是原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);  
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //创建一个新长度的数组。
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

4.对应remove 删除元素操作。如果删除元素在最后一个,不需要移动数组,否则会将被删除元素之后的所有元素都要向前移动,效率比较低。

 //删除
    public E remove(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        modCount++;
        //取出被删除的元素
        E oldValue = (E) elementData[index];
        int numMoved = size - index - 1;
		//移动的数组长度,大于0才需要移动,小于0说明被删元素在最后一个
        if (numMoved > 0)
            //第一个参数是源数组,
            //第二个参数是移动的起始位置:index+1,从被删元素的后一个位置开始
            //第三个参数是目标数组
            //第四个参数是移动目标位置:index,被删除元素的位置
            //第五个参数是移动的数组长度 size - index - 1,从index+1位置开始之后的数组长度
            //最终会调用到native方法进行移动。
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }

5.System.arraycopy方法参数分析。

第二个参数 index+1是被移动数组的起始位置,即被删元素后一个位置

第四个参数index,是被移动数组的起始位置,即被删元素的位置。

最后一个参数size-index-1,被移动数组的长度,即被删元素后一个位置到元素末尾的长度

public static native void arraycopy(java.lang.Object src, int srcPos, java.lang.Object dest, int destPos, int length);

通过对源码的阅读,也许会对ArrayList有一个更加直接的了解。

到此这篇关于Java ArrayList源码深入分析的文章就介绍到这了,更多相关Java ArrayList内容请搜索码农之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持码农之家!


参考资料

相关文章

  • java中实现创建目录与创建文件的操作实例

    发布:2023-04-25

    用Java创建文件或目录非常简单,下面这篇文章主要给大家介绍了关于java中实现创建目录与创建文件的操作实例,文中通过实例代码介绍的非常详细,需要的朋友可以参考下


  • Java实现随机10道10以内加减法的代码详解

    发布:2019-11-16

    这篇文章主要介绍了Java实现随机出题,10道10以内加减法计算,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习


  • java日期时间操作工具类

    发布:2023-01-03

    给网友朋友们带来一篇关于java的教程,这篇文章主要为大家详细介绍了java日期时间操作工具类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • Java实现文件加密解密功能实例详解

    发布:2020-01-13

    这篇文章主要介绍了Java实现文件的加密解密功能,结合具体实例形式详细分析了java针对文件的读取、判断、加密、解密等相关步骤与操作技巧,需要的朋友可以参考下


  • java数据类型转换陷阱包括列表陷阱

    发布:2022-10-20

    给网友朋友们带来一篇关于java的教程,这篇文章主要介绍了java数据类型转换的一些陷阱,包括基本数据类型转换列表陷阱,基本上这一篇就把常见的问题就给大家分享一下


  • 图文详解如何将java编写的程序转为exe文件

    发布:2023-04-25

    我们写的程序,要让小伙伴打开即用,可以将java程序生成可执行文件,下面这篇文章主要给大家介绍了关于一步步教你如何将java编写的程序转为exe文件的相关资料,需要的朋友可以参考下


  • JavaScript封装的常用工具类库bee.js用法详解【经典类库】

    发布:2022-07-07

    给网友们整理关于JavaScript的教程,这篇文章主要介绍了JavaScript封装的常用工具类库bee.js用法,结合实例形式详细分析了经典类库bee.js常见的手机、身份证、邮箱校验,以及字符串操作、四则运算、正则验证等相关操作的封装与使用


  • 学习Array和ArrayList的区别与联系

    发布:2020-03-19

    下面小编就为大家带来一篇详谈Array和ArrayList的区别与联系。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧


网友讨论