ArrayList底层实现原理「建议收藏」

ArrayList底层实现原理「建议收藏」ArrayList简介ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高。源码分析创建了一个大小为0的数组,在后面会用到。声明了一个数组。ArrayList的无参构造方法,将前面声明创建的大小为0的数组赋给elementData数组。这是ArrayList的有参构造方法,传入一个int类型的变量,相当于我们在使用arrayList的时候指定list的大小

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

ArrayList简介
ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高。

源码分析

在这里插入图片描述

创建了一个大小为0的数组,在后面会用到。

在这里插入图片描述

声明了一个数组。
在这里插入图片描述

ArrayList的无参构造方法,将前面声明创建的大小为0的数组赋给elementData数组。

在这里插入图片描述

这是ArrayList的有参构造方法,传入一个int类型的变量,相当于我们在使用arrayList的时候指定list的大小。

如果传入的参数大于0,则新建一个initialCapacity大小的数组。

在这里插入图片描述

传入值等于0的话,将这个空数组给elementData。

下面我们来看add()方法的源码:

在这里插入图片描述

使用到了一个size的参数,先看ensureCapacityInternal方法。

在这里插入图片描述

size参数在前面进行了声明,作用是标识该数组的大小的。

在这里插入图片描述

先执行了calculateCapacity方法,将数组和原先数组大小+1的数值传入。

在这里插入图片描述

对数组进行判断,判断该数组是否为空,在这里插入图片描述
,这是一个空的数组,在前面声明过,如果现存的数组等于空的,我们就返回一个数值,在这里插入图片描述
,第一个变量是常量10,第二个是我们前面传入进来的,比较它俩的大小,返回大的数值。

如果不为空的话,我么直接返回前面方法传入的数值。进入ensureExplicitCapacity()方法。

在这里插入图片描述

modCount是前面声明的变量,初始值为0。
在这里插入图片描述

首先进行判断,如果新长度减去数组原先的长度大于0,我们则调用grow方法,并将新长度传入进去。

在这里插入图片描述

这里就是ArrayList底层数组扩容的核心代码。
在这里插入图片描述

新长度是旧长度加上旧长度的0.5,所以ArrayList底层数组每次扩容的大小都是1.5倍。

第一个if,如果新创建的长度小于传入的数组长度,那么就更新newCapacity的值为minCapacity。

第二个if,如果新数组长度减去最大的数组长度大于0的话,会进入hugeCapacity再次进行判断,返回Integer的最大长度,或者Integer的最大长度-8的长度。
在这里插入图片描述

之后完成数组复制,至此,ArrayList的底层扩容已经实现。

添加的方法说完了,下面我们来看看删除的方法。

在这里插入图片描述

删除是每次进行数组复制,然后让旧的elementData置为null进行垃圾回收,代码很简单,一看就懂,但是我们可以从源码中去发现使用技巧。

查询的方法就更简单了,直接返回查询的对应数组中的值。

下面我们来自己写一个简易的ArrayListDemo。

/** * 作者:LKP * 时间:2018/7/13 */
public class ArrayListDemo { 
   
    private Object[] arry;     //数组
 
    private int size = 0;      //下标
 
    public ArrayListDemo(){ 
   
        this.arry = new Object[10];
    }
 
    public ArrayListDemo(int size) throws Exception { 
   
        if(size > 0)
            this.arry = new Object[size];
        else
            throw new Exception("长度不允许小于零!");
    }
 
    //新增
    public void add(Object number){ 
   
        if(size >= arry.length){ 
   
            int length = arry.length;
            Object[] newArry = new Object[length];
            for(int i=0; i<arry.length; i++){ 
   
                newArry[i] = arry[i];
            }
            length = (length*3)/2+1;        //更新数组长度
            arry = new Object[length];      //对原有数组进行扩容
            for(int j=0; j<newArry.length; j++){ 
   
                arry[j] = newArry[j];
            }
            newArry = null;     //释放该数组
        }
        arry[size] = number;
        size++;
    }
 
    //读取
    public Object get(int index) throws Exception { 
   
        if(index >= 0)
            return arry[index];
        throw new Exception("下标不符合要求!");
    }
 
    //获得大小
    public int getSize(){ 
   
        int count = 0;
        for(int i=0; i<arry.length; i++){ 
   
            if(arry[i] != null){ 
   
                count++;
            }
        }
        return count;
    }
}

客户端代码:

/** * 作者:LKP * 时间:2018/7/13 */
public class demo { 
   
    public static void main(String[] args){ 
   
        ArrayList ls = new ArrayList();
        ArrayListDemo list = new ArrayListDemo();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        for(int i=0; i<list.getSize(); i++) { 
   
            try { 
   
                System.out.println("List的值:"+list.get(i));
            } catch (Exception e) { 
   
                e.printStackTrace();
            }
        }
    }
}

运行结果:

在这里插入图片描述

总结
1.在声明时尽量指定长度。

2.ArrayList底层是数组,数组是适合查询的,因为数组每个元素的内存空间是固定的,每次查询时,只需要去查询对应位置的内存空间,就可以很快找到相应的值。而数组不擅长的是添加和删除。试想,集合长度是100000,而我们在第2个位置添加了一个元素,导致的结果是从第3个开始后面每一个元素都要往后串一个元素内存空间那么大的位置。删除刚好相反,是向前串一个位置,这样的效率是很低的,元素越多,效率越低。而频繁的添加和删除,适用链表——LinkedList。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/168692.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Snap7 西门子S7系列PLC的通信库 简介[通俗易懂]

    Snap7 西门子S7系列PLC的通信库 简介[通俗易懂]目录简介参考Snap7简介Snap7用途适用系统支持语言西门子S7通信介绍Snap7组件Sanp7APISnap7PythonSnap7安装PLC设置连接PLC读取数据发送数据Sanp7C/C++node.js简介最近在开发一个项目,作为技术帝,已经完成工艺、机械设计的设计,项目过多,也是为了让自己更加????叉,就开始尝试做电气制图和PLC编程。结合物联网的发展,有一种想法,将数据传…

    2022年10月23日
    0
  • @JsonFormat、@JSONField、@DateTimeFormat的使用以及其区别[通俗易懂]

    三者出处1、JsonFormat来源于jackson,Jackson是一个简单基于Java应用库,Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。Jackson所依赖的jar包较少,简单易用并且性能也要相对高些,并且Jackson社区相对比较活跃,更新速度也比较快。2、JSONField来源于fastjson,是阿里巴巴…

    2022年4月17日
    51
  • Java分页查询(真分页)

    Java分页查询(真分页)Java分页查询(真分页)

    2022年4月25日
    35
  • AGI:走向通用人工智能的【生命学&哲学&科学】第一篇——生命、意识、五行、易经、量子

    AGI:走向通用人工智能的【生命学&哲学&科学】第一篇——生命、意识、五行、易经、量子AGI:走向通用人工智能的【生命学&哲学&科学】第一篇——生命、意识、五行、易经、量子经典的物理统一在原子上,量子的物理统一在量子上,化学统一在元素上,而生命统一在DNA上,DNA本身拆干了,其实就是一群元素,按照经典物理和量子物理所进行的组合。科学本质上是一种经验主义的认识论,属于哲学的一个分支。量子理论,要通过哲学语言,量子属于形而上看不到、摸不着的东西。元气的基本五行,是世界万物的行成与演变的方式。生命的本质是化学,化学的本质是物理,物理的本质用数学描述,数学的本质是由我们的某种语言写出

    2022年6月3日
    35
  • VMware的Linux虚拟机桥接模式突然上不了网解决方法「建议收藏」

    VMware的Linux虚拟机桥接模式突然上不了网解决方法「建议收藏」虚拟机的IP、子网掩码、默认网关、DNS设置得与宿主机在同一子网,虚拟机桥接模式一直以来都可以正常上网,但突然有一天就不能上网了,还死活ping不通外网、网关。此时只需将VM的虚拟网络编辑器中关于桥接模式的设置改一下就行了,具体步骤如下。1、右键点击window系统网络状态那个图标,单击打开“网络和Internet”设置。2、点击更改适配器选项。3、查看window系统联网使用的网卡,记住设备名。4、打开VMware,点击编辑>虚拟网络编辑器。5、在弹出界面点击更改设置。6、桥接模式选

    2022年5月29日
    156

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号