ArrayList(扩容机制)

news2024/11/19 1:42:54

文章目录

  • 一、前言
  • 二、ArrayList扩容机制
    • 1、适用于什么场景?
    • 2、ArrayList特点
    • 3、ArrayList扩容机制
      • 3.1、内存分配的效率:
      • 3.2、数据迁移的代价
      • 3.3、性能和空间的平衡
  • 三、总结

一、前言

对于ArrayList集合可能大家并不陌生,但ArrayList集合的扩容机制大家是否了解呢?我们今天着重来看看

二、ArrayList扩容机制

1、适用于什么场景?

检索比较多的场景

2、ArrayList特点

1、ArrayList集合底层采用了数据这种数据结构,是Object类型
2、ArrayList的默认初始容量为10,扩容因子为1.5
3、建议给定一个预估计的初始化容量,减少数组扩容的次数,这是ArrayList集合比较重要的优化策略.因为在在扩容的同时需要将原来数组中的数据复制到新数组里,但如果要插入大量数据时,赋值数组的形式效率很低,所以大多数情况下会使用带参构造函数,传入一个预估计容量,提前定义好容量。
4、ArrayList是非线程安全的

import java.util.ArrayList;
import java.util.List;

public class ListTest {
public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("b");//第一个,索引下标0
    list.add("d");
    list.add("c");
    list.add("a");
    list.add("d"); //允许使用重复元素

    System.out.println(list);  //输出结果:[b, d, c, a, d]
    System.out.println(list.get(2));  //输出指定下标的元素,输出结果:c

    list.add(1,"f");//在指定索引下标位置添加元素
    System.out.println(list); //输出结果:[b, f, d, c, a, d],原来下标为1和1之后的下标索引位置的元素自动向后移动

    List<String> a = new ArrayList<String>();
    a.add("123");
    a.add("456");
    list.addAll(2,a);  //在指定索引下标的位置插入集合
    System.out.println(list);//输出结果:[b, f, 123, 456, d, c, a, d]

    //获取指定元素在集合中第一次出现的索引下标
    System.out.println(list.indexOf("d")); //输出结果:4
    //获取指定元素在集合中最后一次出现的索引下标
    System.out.println(list.lastIndexOf("d"));//输出结果:7

    list.remove(2);  //根据指定的索引下标移除元素
    System.out.println(list);  //输出结果:[b, f, 456, d, c, a, d]

    list.set(1,"ff"); //根据指定的索引下标修改元素
    System.out.println(list); //输出结果:[b, ff, 456, d, c, a, d]

    //根据索引下标的起始位置截取一段元素形成一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
    List<String> sublist= list.subList(2,4);
    System.out.println(sublist);//输出结果:[456, d]

    System.out.println(list.size());//输出结果7
    }
}
import java.util.LinkedList;
import java.util.List;

public class ListTest {
public static void main(String[] args){
    List l1 = new LinkedList();
    for(int i = 0;i<=5;i++){
    l1.add("a"+i);
    }

    System.out.print(l1);
    l1.add(3,"a100");
    System.out.println(l1);
    l1.set(6,"a200");
    System.out.println(l1);
    System.out.print((String)l1.get(2)+" ");
    System.out.println(l1.indexOf("a3"));
    l1.remove(1);
    System.out.println(l1);
    }
}

输出结果:

[a0,a1,a2,a3,a4,a5]

[a0,a1,a2,a100,a3,a4,a5]

[a0,a1,a2,a100,a3,a4,a200]

a2 4

[a0,a2,a100,a3,a4,a200]

3、ArrayList扩容机制

ArrayList的使用前不需要像数组一样提前定义大小空间,容量是随着使用时自动增长的,那为什么在使用ArrayList的add方法添加元素的时候底层还需要判断集合的容量是否能够放下要添加的元素呢?又没有定义固定大小直接放进去不就好了吗?

add方法添加分为三步:
①、判断集合容量是否满足添加的元素
②、添加元素
③、集合长度+1
在这里插入图片描述
解答:
用户不需要提前定义大小,那是因为底层默认已经定义好了大小。其实是有一个边界值的,并不是无限增长的。使用时增加,是因为底层有扩展因子(扩容因子是1.5),当数量达到数组的百分之多少的时候就会扩容。ArrayList默认的初始大小是10
在这里插入图片描述
在这里插入图片描述

问题:大家可以思考思考为什么ArrayList底层扩容因子是1.5?为什么不是1.3、2.4……?

ArrayList的底层扩容因子是1.5,而不是其他数字,是为了在平衡内存使用和性能之间找到一个合适的折中方案。下面是一些原因:

3.1、内存分配的效率:

扩容因子的选择会影响内存分配的效率。如果扩容因子过小,每次扩容都只增加少量的容量,这会导致频繁的内存分配操作,增加了时间和空间的开销。而如果扩容因子过大,每次扩容都会增加大量的容量,这可能会导致浪费过多的内存。1.5是一个相对较小的扩容因子,可以在一定程度上平衡内存使用和性能。

3.2、数据迁移的代价

当ArrayList需要扩容时,需要将原有数据迁移到新的更大的数组中。扩容因子的选择会影响数据迁移的频率和代价。较小的扩容因子会导致更频繁的数据迁移,而较大的扩容因子会减少数据迁移的次数。1.5作为一个相对较小的扩容因子,可以在一定程度上减少数据迁移的代价。

3.3、性能和空间的平衡

ArrayList旨在提供高效的随机访问和动态增长的能力。选择1.5作为扩容因子可以在一定程度上平衡性能和空间的需求。较小的扩容因子可以减少内存的浪费,而较大的扩容因子可以减少内存分配的频率。

综上所述,ArrayList的特点如下

  • 初始容量:当你创建一个ArrayList对象时,它会分配一个初始容量(默认为10,可以通过构造函数设置初始容量)。这个初始容量表示ArrayList内部的数组可以容纳的元素数量。
  • 添加元素:当你向ArrayList中添加元素时,它首先检查是否需要扩容。这是通过比较ArrayList内部的元素数量与当前容量之间的关系来完成的。
  • 扩容条件:通常,ArrayList会在元素数量达到当前容量时触发扩容操作。当元素数量等于或超过当前容量时,ArrayList就会启动扩容机制
  • 扩容策略:ArrayList会创建一个新的更大的数组,通常情况下,新数组的容量会是当前容量的1.5倍(这个倍数可以通过ensureCapacity方法或构造函数的参数进行调整)。然后,ArrayList会将所有现有元素复制到新数组中。
  • 复制元素:将元素复制到新数组中可以使用System.arraycopy方法或类似的机制。这个操作的时间复杂度是O(n),其中n是元素的数量。
  • 更新容量:一旦所有元素都复制到新数组中,ArrayList会将内部的数组引用指向新数组,并且更新容量为新数组的容量。
  • 添加新元素:最后,ArrayList会将新元素添加到新数组中,现在新数组的容量足够容纳所有元素。
  • 扩容成本:由于扩容操作需要复制元素到新数组,因此它会引入一些性能开销。为了减少扩容的频率,通常可以在创建ArrayList时就指定一个足够大的初始容量,以避免多次扩容。

三、总结

ArrayList的扩容机制是自动管理的,它会在需要时动态地扩展内部数组的容量,以适应不断增加的元素。这个机制确保了ArrayList在添加元素时能够保持高效性能,但也需要考虑到扩容操作可能引入的性能开销。因此,在处理大量数据时,可以通过手动设置足够大的初始容量来减少扩容的次数,从而提高性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/962313.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Camera | 12.瑞芯微摄像头自动焦距马达驱动移植

本为你主要讲解如何让摄像头ov13850支持自动对焦功能。 摄像头的对角主要通过VCM马达驱动芯片DW9714来实现的。 一、环境 soc : rk3568 board: EVB1-DDR4-V10 软 件&#xff1a;Android 11 Linux&#xff1a;4.19.232 Camera:ov13850二、DW9714 1.DW9714简介 DW9714专…

企业知识管理的解决方案

人们发现&#xff0c;挖掘知识、创造知识、生产知识&#xff0c;用知识为自己的产品赋予高附加值&#xff0c;才是企业和社会可持续发展的动力之源。所以知识管理越来越受到重视。 知识管理作为一个新兴的管理概念&#xff0c;已经被学术界所接受&#xff0c;但尚未形成一个…

网站用户体验之深度感悟

个性化定制界面和极简版原装界面&#xff0c;哪一个你用起来更加顺手呢&#xff0c;相比之下你更喜欢哪一个&#xff1f; 界面选择&#xff1a; &#xff08;提醒&#xff1a;仅个人感悟。~~&#xff09; 方向一&#xff1a;表明自己的喜好 我个人觉得更喜欢个性化定制界面。…

虚拟机有代理备份、无代理备份是什么?

有代理备份&#xff1a; 在虚拟机内部安装备份代理程序&#xff0c;然后把虚拟机当作物理机一样来进行备份任务。借助虚拟机系统中内置的程序来进行备份的&#xff0c;就像在正常系统中备份那样&#xff0c;借助备份和还原&#xff08;Windows7&#xff09;功能对系统进行备份…

知识图谱笔记:TransE

1 知识图谱介绍 一条知识图谱可以表示为一个三元组(sub,rel,obj)。 举个例子&#xff1a;小明的爸爸是大明&#xff0c;表示成三元组是&#xff08;小明&#xff0c;爸爸&#xff0c;大明&#xff09;。前者是主体&#xff0c;中间是关系&#xff0c;后者是客体。主体和客体统…

layui引入百度地图

<script type"text/javascript" src"//api.map.baidu.com/api?typewebgl&v1.0&ak你的ak"></script> <script src"https://code.bdstatic.com/npm/jquery1.12.4/dist/jquery.min.js"></script> <script src&…

科技驱动产业升级:浅谈制造型企业对MES系统的应用

在科技不断进步的背景下&#xff0c;制造型行业也在持续发展&#xff0c;但随之而来的挑战也不断增加。传统的管理方式已经无法满足企业的需求&#xff0c;因此许多制造型企业开始寻找新的管理模式。制造执行系统&#xff08;MES&#xff09;作为先进的制造信息技术之一&#x…

【微信小程序】父子组件的创建、通信与事件触发;组件生命周期

前言 关于微信小程序中父子组件的创建、传值&#xff0c;以及涉及到的组件生命周期。 使用组件的优点 组件的使用可以提高开发效率并确保功能在各个页面上的应用和修改的一致性。 例如&#xff0c;对于一些重复的功能&#xff0c;比如顶部导航栏或评论区&#xff0c;将其提炼…

MongoDB基础知识点

MongoDB基础知识点 1.MongoDB简介1.1基本信息1.2作用1.3下载 2.MongoDB安装1.Ubuntu22.042.Windows(非msi) 3.MongoDB基本操作1.基本概念2.MongoDB文件增删改查(CURD)1.插入数据2.查询数据3.修改数据4.删除数据5.删除字段 4.MongoDB实战管理系统数据库设计1.设计数据库2.Mongod…

c++ folly::baton

Baton folly::Baton 是 Facebook 开源的一个同步原语&#xff0c;它提供了一种简单而灵活的方式来进行线程间的同步。它属于 Folly 库&#xff0c;是 C 编程语言的一个组件。 Baton 通常用作线程间同步、等待、通知的标识符号&#xff0c;常用姿势是&#xff0c;一些线程调用…

正中优配:红筹股是啥意思?

随着我国经济的高速开展&#xff0c;越来越多的人开始参加到股票出资中。其中&#xff0c;红筹股作为一种特别类型的股票&#xff0c;备受一些出资者的关注&#xff0c;但对于一般出资者来说&#xff0c;红筹股详细含义还不是特别清楚。本文将从多个角度探讨红筹股的含义、特征…

分库分表知识大全及Sharding-JDBC实践

文章目录 一、为什么要分库分表1.1 什么是分库1.2 什么是分表1.3 为什么要分库1.3.1 磁盘存储1.3.2 并发连接支撑 1.4 为什么要分表 二、分库分表解决方案2.1 垂直&#xff08;纵向&#xff09;切分2.1.1 垂直切分优点2.1.2 垂直切分缺点 2.2 水平&#xff08;横向&#xff09;…

了解NAT

局域网内的终端是如何共用一个wan口来上网的&#xff1f; 主要通过NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;协议来实现的 NAT是1994年提出的。当在专用网内部的一些主机本来已经分配到了本地…

无涯教程-Flutter - 数据库

SQLite" class"css-1occaib">SQLite数据库是基于事实和标准SQL的嵌入式数据库引擎&#xff0c;它是小型且经过时间考验的数据库引擎&#xff0c;sqflite软件包提供了许多函数&#xff0c;可以有效地与SQLite数据库一起使用&#xff0c;它提供了操作SQLite数据…

【FreeRTOS】互斥量的使用与逐步实现

在FreeRTOS中&#xff0c;互斥量是一种用于保护共享资源的同步机制。它通过二进制信号量的方式&#xff0c;确保在任意时刻只有一个任务可以获取互斥量并访问共享资源&#xff0c;其他任务将被阻塞。使用互斥量的基本步骤包括创建互斥量、获取互斥量、访问共享资源和释放互斥量…

nepctf2023 部分web复现

目录 <1> EZJAVA_CHECKIN(shiro550) <2> 独步天下-转生成为镜花水月中的王者(环境变量提权) <3> 独步天下-破除虚妄_探见真实(Venom代理&ping%0a绕过rce&c文件描述符未关闭连接父进程修改文件权限) <4> 独步天下-破除试炼_加冕成王(tp6rceu…

STM32F103C8T6引脚图及引脚功能说明

内容部分引用STM32F103C8T6引脚图_karwen2020的博客-CSDN博客_stm32引脚图

1688采集商品主图,价格,规格接口

采集1688商品主图&#xff0c;价格接口&#xff0c;点击测试 在如今的电商时代&#xff0c;越来越多的人开始选择在1688平台上寻找商品&#xff0c;而采集软件的方式也有很多种&#xff0c;但是在市面上&#xff0c;各种采集软件琳琅满目&#xff0c;令人眼花缭乱&#xff0c;…

【玩玩Vue】使用el-menu作为菜单时,通过一二级路由控制菜单高亮

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、Vue路由二、路由一级控制高亮&#xff08;常用&#xff09;1.vue中路由文件2.网址样式3.Vue文件4.$route的内容 三、路由二级控制高亮…

基于白鲸算法优化的BP神经网络(预测应用) - 附代码

基于白鲸算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于白鲸算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.白鲸优化BP神经网络2.1 BP神经网络参数设置2.2 白鲸算法应用 4.测试结果&#xff1a;5.Matlab代码 摘要…