当前位置: 首页 > news >正文

Java源码分析(三)ArrayList

    ArrayList是我们经常用到的一个集合类。数组在创建时就要给一个明确的大小,而ArrayList的长度是可以动态调整的,因此,也叫动态数组。那么本篇我们一起学习下ArrayList的源码。

一、创建ArrayList

    首先,我们从创建ArrayList开始。上面也提到过,ArrayList的长度是可以动态调整的,我们通常创建一个不指定容量的数组。例如如下代码,创建一个空的ArrayList:

List<String> list = new ArrayList<>();

    看下构造方法的源码:

    代码注释说:构建一个容量为10的空List。List是基于数组来实现的,可以看到,构造方法这里创建了一个空的数组。咦?没看到容量为10啊,这个后面我们会介绍到。

二、添加元素

1、add

    创建好一个空的ArrayList后,我们调用add方法往里面添加元素,如下:

list.add("a");
list.add("b");
list.add("c");

    看下add方法的源码:

    核心是调用了红框中的add方法,看下其实现:

    可以看到,判断size是否达到了数组的长度,如果达到了长度,调用grow()方法扩容,然后把元素赋值给size的位置,对size加1。 简单总结:

   1扩容2赋值3加一。

2、扩容原理

    接下来,看下grow函数是怎么扩容的:

    基于当前的数组和新的容量(size + 1)复制新的容量的数组 ,看下newCapacity函数是如何去确定新的数组的容量的:

    代码注释机翻一下:返回至少与给定最小容量一样大的容量。如果足够的话,返回增加50%的当前容量。除非给定的最小容量大于MAX_ARRAY_SIZE,否则不会返回大于MAX_ARRAY_SIZE的容量。 在扩容的操作里面,用到了几个常量:

private static final int DEFAULT_CAPACITY = 10;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
@Native public static final int   MAX_VALUE = 0x7fffffff;

    所以,扩容是这样的过程:

1、new = old + old *(old / 2): 扩容50%得到newCapacity

2、如果newCapacity - 最小容量(即size + 1)<=0,返回给定最小容量。需要注意,如果空的数组,那么返回的容量是10。

这里再详细解释下:

    往一个空的list去add元素,size = 0,minCapacity = size + 1,计算出的newCapacity = 0 + 0 = 0,这时候newCapacity - minCapacity = -1,满足了条件。然后这时候判断数组是空的,所以返回了max(10,1),也就是10。

    那么接下来继续add元素,容量为10,因此在添加到10个元素之前,都不会扩容。直到添加第11个元素的时候,触发扩容,这时候就是扩容50%了。

return (newCapacity - MAX_ARRAY_SIZE <= 0)? newCapacity: hugeCapacity(minCapacity);

    绝大多数情况下返回newCapacity,也就是扩容50%的容量,当新的容量超过MAX_ARRAY_SIZE,会走到hugeCapacity的逻辑:

总结下,ArrayList添加元素时的扩容流程:

1、新建的ArrayList容量10其实不准确,为0。

2、当首次添加元素时,容量扩展为默认容量10。

3、一直到添加满10个元素之前,都不会再次扩容,维持10的容量。

4、添加第11个元素时,会触发扩容50%;直到用完容量前,不会继续扩容,以此类推。

3、扩容demo验证 

    接下来,我们写一个小的demo验证下扩容的流程:

public class ArrayListTest {public static void main(String[] args) {// 创建一个空的ArrayListArrayList<Integer> list = new ArrayList<>();System.out.println("初始容量:" + getArrayListCapacity(list));for (int i = 0; i < 11; i++) {list.add(i);System.out.println("add第" + (i + 1) + "个元素,容量:" + getArrayListCapacity(list));}}/*** 反射获取Arraylist的容量* @param list* @return*/private static int getArrayListCapacity(ArrayList<?> list) {try {java.lang.reflect.Field capacityField = ArrayList.class.getDeclaredField("elementData");capacityField.setAccessible(true);return ((Object[]) capacityField.get(list)).length;} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();return -1;}}

三、移除元素 

    移除元素使用remove方法,如下:

 (1)检验index,index非法则会抛出异常:IndexOutOfBoundsException

(2)把index的元素赋值给oldValue,并在程序最后返回该element

(3)调用fastRemove方法移除第index个元素

     看下fastRemove方法:

 

    基于当前的数组去把指定范围的数据copy到另一个数组,并把

http://www.lryc.cn/news/227979.html

相关文章:

  • 冒泡排序
  • docker基于debian11基础环境安装libreoffice
  • Intel Devkit Call for Paper Challenge - Advanced Award
  • 【正点原子STM32连载】 第五十章 FATFS实验 摘自【正点原子】APM32F407最小系统板使用指南
  • 12. 机器学习——评价指标
  • 代码随想录算法训练营第23期day45|70. 爬楼梯 (进阶)、322. 零钱兑换、279.完全平方数
  • uniapp公共css
  • C语言—i++、++i、条件运算符、goto语句、注释
  • Java自学第8课:电商项目(3) - 重新搭建环境
  • 深度学习_11_softmax_图片识别代码原理解析
  • Java Web——前端HTML入门
  • 华为ensp:为vlan配置ip
  • laravel8-rabbitmq消息队列-实时监听跨服务器消息
  • git清除历史提交记录保持本地文件不变
  • SOME/IP学习笔记2
  • python实现FINS协议的TCP服务端(篇一)
  • 利用uni-app 开发的iOS app 发布到App Store全流程
  • 5个高质量的实用办公软件,每一款都是良心推荐
  • 基于GPTs个性化定制SCI论文专业翻译器
  • Final Cut Pro X for Mac:打造专业级视频剪辑的终极利器
  • c++分割路径的字符串,得到 目录 文件名 扩展名
  • ABAP OpenSQL 分页处理
  • kubeasz一键部署k8s集群
  • 高性能图表库LightningChart JS v5.0 - 轻松实现图表自定义布局
  • 深度学习的集体智慧:最新发展综述
  • Java之“数字困境”:资产管理项目中的Bug追踪与启示
  • 小程序微信登录授权突然没反应的原因和解决方案
  • 文本提交时如何使用PHP替换回车为br
  • 安全框架SpringSecurity-1(认证入门数据库授权)
  • 【MybatisPlus】条件构造器、自定义SQL、Service接口