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

Java集合源码解析之ArrayList

目录

1.ArrayList源码解析

整体流程图概览

构造方法

无参构造方法

有参构造方法

add()

重点子方法grow(xxx)

2.LinkedList 源码解析

3.HashMap源码解析****※


1.ArrayList源码解析

整体流程图概览

构造方法

        arrayList的构造方法就做一件事情,就是初始化一下储存数据的容器,其实本质上就是一个数组,在其中就叫elementData

无参构造方法

/*** 构造一个空容量的数组(DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {})*/public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}

有参构造方法

   /*** Constructs an empty list with the specified initial capacity.** @param initialCapacity the initial capacity of the list* @throws IllegalArgumentException if the specified initial capacity*                                  is negative*/public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;// /将自定义的容量大小当成初始化elementData的大小} else {throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);}}

add()

/*** 新增元素操作,执行如下操作:*      List list = new ArrayList();*      list.add("a1");*/// eg1:第一次新增元素e="a1"public boolean add(E e) {/** 确定是否需要扩容,如果需要,则进行扩容操作*/ensureCapacityInternal(size + 1); // eg1:size=0// eg1:size=0,elementData[0]="a1",然后a自增为1elementData[size++] = e;return true;}// eg1:第一次新增元素,size=0,则:minCapacity=size+1=0+1=1private void ensureCapacityInternal(int minCapacity) {// eg1:第一次新增元素,calculateCapacity方法返回值为DEFAULT_CAPACITY=10ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}/*** 计算ArrayList的容量,如果elementData数组中没有已存储的元素,则返回默认值10,否则,返回minCapacity。*/// eg1:第一次新增元素,elementData={} minCapacity=1private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // DEFAULTCAPACITY_EMPTY_ELEMENTDATA={}return Math.max(DEFAULT_CAPACITY, minCapacity); // eg1:return 10return minCapacity;}/*** 确保明确的ArrayList的容量*/// eg1:minCapacity=10private void ensureExplicitCapacity(int minCapacity) {/** 变化次数加1 */modCount++; // eg1: modCount++后,modCount=1/** 如果所需的【最小容量】大于elementData数组的容量,则进行扩容操作 */if (minCapacity - elementData.length > 0)  // eg1:elementData.length=0grow(minCapacity); // eg1:minCapacity=10}

重点子方法grow(xxx)

grow(xxx); arrayList核心的方法,能扩展数组大小的真正秘密

/*** 增加容量以确保它至少可以容纳最小容量参数指定的元素数量。*/// eg1:minCapacity=10private void grow(int minCapacity) {/** 原有数组elementData的长度 */int oldCapacity = elementData.length; // eg1:oldCapacity=0/*** A >> 1 等于 A/2* eg: 3 >> 1 = 3/2 = 1*     4 >> 1 = 4/2 = 2* ------------------------* A << 1 等于 A*2* eg: 3 << 1 = 3*2 = 6*     4 << 1 = 4*2 = 8** 000100 >> 1 = 000010* 000100 << 1 = 001000*//** 新增oldCapacity的一半整数长度作为newCapacity的额外增长长度 */int newCapacity = oldCapacity + (oldCapacity >> 1); // eg1:newCapacity=0+(0>>1)=0/** 新的长度newCapacity依然无法满足需要的最小扩容量minCapacity,则新的扩容长度为minCapacity */if (newCapacity - minCapacity < 0) // eg1:truenewCapacity = minCapacity; // eg1:newCapacity=10/** 新的扩容长度newCapacity超出了最大的数组长度MAX_ARRAY_SIZE(huge:巨大的) */if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);/** 扩展数组长度为newCapacity,并且将旧数组中的元素赋值到新的数组中 */elementData = Arrays.copyOf(elementData, newCapacity); // eg1:newCapacity=10, 扩容elementData的length=10}private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) { // overflowthrow new OutOfMemoryError();}return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;}

        正常情况下会扩容1.5倍,特殊情况下(新扩展数组大小已经达到了最大值)则只取最大值。当我们调用add方法时,实际上的函数调用如下:

                                                     

 

重点总结 


1)arrayList可以存放null。
2)arrayList本质上就是一个elementData数组。
3)arrayList区别于数组的地方在于能够自动扩展大小,其中关键的方法就是gorw()方法。
4)arrayList中removeAll(collection c)和clear()的区别就是removeAll可以删除批量指定的元素,而clear是全是删除集合中的元素。
5)arrayList由于本质是数组,所以它在数据的查询方面会很快,而在插入删除这些方面,性能下降很多,有移动很多数据才能达到应有的效果
6)arrayList实现了RandomAccess,所以在遍历它的时候推荐使用for循环。

部分参考:ArrayList源码解析-CSDN博客     

 

2.LinkedList 源码解析

Java集合源码解析之LinkedList-CSDN博客

3.HashMap源码解析****※

点击下方链接获取

HashMap源码解析

http://www.xdnf.cn/news/1429417.html

相关文章:

  • 网络共享协议
  • 【Vue2 ✨】 Vue2 入门之旅(五):组件化开发
  • 车载刷写架构 --- ECU软件更新怎么保证数据的正确性?
  • MATLAB矩阵及其运算(三)矩阵的创建
  • 应用层:HTTP/HTTPS协议
  • 【Python数据可视化:Matplotlib高级技巧】
  • 高效数据传输的秘密武器:Protobuf
  • 京东商品详情商品详情接口技术实现:从数据抓取到结构化解析全方案
  • LeetCode 777.在LR字符串中交换相邻字符
  • C++ 面试高频考点 力扣 852. 山脉数组的峰顶索引 二分查找 题解 每日一题
  • 【Linux笔记】命令行与vim基础
  • 单元测试总结2
  • MTK Linux DRM分析(二十六)- MTK mtk_drm_ddp_xxx.c
  • Spring Boot 3.5.3 集成 Log4j2 日志系统
  • 从spring MVC角度理解HTTP协议及Request-Response模式
  • 异常处理小妙招——1.别把“数据库黑话”抛给用户:论异常封装的重要性
  • 图像 OSD层数据 显示--OSD LOGO单色黑色显示,按区域大小申请MMZ内存的优缺点分析
  • 2022版Unity创建时没有2D灯光(2D Light),没有Global LIght2D怎么办?
  • Java集合遍历的方法有哪些
  • 使用Spark计算WordCount
  • 美团 LongCat 开源大模型60 亿参数 MoE 架构,赋能开发者加速 AI 应用落地
  • vue2中如何使用Ant Design Vue 中的 Tooltip 文字提示
  • 242. 有效的字母异位词| 349. 两个数组的交集
  • 通信中FDD和TDD的区别
  • 【JavaEE】多线程案例
  • 使用 Python 的 SymPy 进行符号计算
  • 机器学习回顾——决策树详解
  • 详解Grafana k6 的阈值(Thresholds)
  • FPGA时序分析(三)--基础知识
  • Leetcode_206.反转链表(递归)