自己做网站好不好/网络营销公司名称
时隔两年,重新读ArrayList源码,轻松了很多,以问题的方式记录一下收获
- 装饰器模式
注释中提到ArrayList本身不是线程安全的,注释如下:
* <p><strong>Note that this implementation is not synchronized.</strong>* If multiple threads access an <tt>ArrayList</tt> instance concurrently,* and at least one of the threads modifies the list structurally, it* <i>must</i> be synchronized externally. (A structural modification is* any operation that adds or deletes one or more elements, or explicitly* resizes the backing array; merely setting the value of an element is not* a structural modification.) This is typically accomplished by* synchronizing on some object that naturally encapsulates the list.** If no such object exists, the list should be "wrapped" using the* {@link Collections#synchronizedList Collections.synchronizedList}* method. This is best done at creation time, to prevent accidental* unsynchronized access to the list:<pre>* List list = Collections.synchronizedList(new ArrayList(...));</pre>
如果要想做到线程安全,需要对某个对象加锁的方式来实现,实现应当如下
synchronized(ojb) {list.add(item);
}
如果没有这么做,可以使用Collections.synchronizedList对ArrayList包装,并且最好是在一开始定义list的时候就进行包装,避免有的地方使用了未包装的原始list,代码如下:
List list = Collections.synchronizedList(new ArrayList(...));
- 类签名里既然继承了AbstractList,为什么还要写implements List
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
应该是作者写错了,后来没改回来只是觉得没有必要且保持和旧版本的一致了。参考博客 以及 stackOverFlow问答
- DEFAULTCAPACITY_EMPTY_ELEMENTDATA
这是在无参构造函数使用的存储数据,默认不分配数组且空数组也复用,这内存节省到极致了,值得学习。
/*** Shared empty array instance used for default sized empty instances. We* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when* first element is added.*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** Constructs an empty list with an initial capacity of ten.*/public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
- 存储结构:Object[] elementData
为什么使用Object?这个是java对于泛型的使用上有一些约束。如果直接创建T[]数组,会报错,因为编译器会进行类型擦除,并不能知道这个T类型是什么。所以干脆创建Object[]数组。(这个参考自 ArrayList 解析)
鉴于泛型擦除,list只能做编译期的类型校验,运行时是无法校验的,除非有类型强转。
public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(1);List list1 = list;list1.add("xx");System.out.println(list);}
输出:[1, xx]
- elementData前的transient关键字
意思是序列化时忽略,writeObject和readObject单独实现。这两个方法必须声明为private,在java.io.ObjectStreamClass#getPrivateMethod()方法中通过反射获取到writeObject()这个方法。
elementData定义为transient的优势:自己根据size序列化真实的元素,而不是根据数组的长度序列化元素,减少了空间占用。 - ensureExplicitCapacity直接进行了modCount++,我觉得不妥
源码如下,其实下面的if语句为false的时候,grow不会执行,也就不会对list进行修改,所以modCount理论上不应该增加。
结合add和remove方法来看,这么写是因为add和remove方法会调用ensureExplicitCapacity,所以将modCount++的动作下沉了。
但是public方法ensureCapacity,也调用了ensureExplicitCapacity,而不一定会产生结构修改,除非size需要调整。所以这里的语义不太合理了。
/*** 对外提供的方法,可以通过调用这个方法,在要写入大批数据之前进行容量保障,避免出现频繁扩容**/public void ensureCapacity(int minCapacity) {int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)// any size if not default element table? 0// larger than default for default empty table. It's already// supposed to be at default size.: DEFAULT_CAPACITY;if (minCapacity > minExpand) {ensureExplicitCapacity(minCapacity);}}/*** 内部私有实现**/private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}
- MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
最大大小设置的是int最大值-8,一堆讨论为什么要减8的以及实际上容量也能设置为int最大值的,这个暂时跳过。
想到了另外一个问题,size的返回结果是int,那超出int怎么办?为什么不能设置为long?不能设置为long的原因很好理解,因为没必要,一般不会这么大,而且用long就会占用更多内存。那么超出int怎么办?没找到方法,或许自行设计一个复杂结构 - 扩容是newCapacity = oldCapacity + (oldCapacity >> 1),每次扩50%
- rangeCheckForAdd
针对add和addAll方法会多校验一下index<0,为什么remove不需要校验呢?不太理解 - 代码风格:a方法调用了b方法,b方法写在a方法后面,更容易阅读。
- fastRemove方法
去掉了index校验,只供内部使用,真的是太细了。对性能压榨到了极致
/*** 公共方法,删除指定index的元素,有range校验**/public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue;}/*** 公共方法,删除指定对象,在查找到对象之后,获取其index,通过调用fastRemove进行删除**/public boolean remove(Object o) {if (o == null) {for (int index = 0; index < size; index++)if (elementData[index] == null) {fastRemove(index);return true;}} else {for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {fastRemove(index);return true;}}return false;}/*** 私有方法,删除指定index的元素,只供内部使用,因此没有做range校验**/private void fastRemove(int index) {modCount++;int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its work}
- batchRemove用了读写双指针来实现数据删除过程中的就地挪动
有时候做算法题就会看到一些双指针解决的问题,jdk源码里就有相应实现
/*** 删除给定集合的元素,它调用了batchRemove方法**/public boolean removeAll(Collection<?> c) {Objects.requireNonNull(c);return batchRemove(c, false);}/*** 保留给定集合的元素,它调用了batchRemove方法**/public boolean retainAll(Collection<?> c) {Objects.requireNonNull(c);return batchRemove(c, true);}/*** 批量删除方法,可以通过complement来控制传入的集合中的原始是需要删除还是保留* r、w双指针实现就地修改**/private boolean batchRemove(Collection<?> c, boolean complement) {final Object[] elementData = this.elementData;int r = 0, w = 0;boolean modified = false;try {for (; r < size; r++)if (c.contains(elementData[r]) == complement)elementData[w++] = elementData[r];} finally {// Preserve behavioral compatibility with AbstractCollection,// even if c.contains() throws.if (r != size) {System.arraycopy(elementData, r,elementData, w,size - r);w += size - r;}if (w != size) {// clear to let GC do its workfor (int i = w; i < size; i++)elementData[i] = null;modCount += size - w;size = w;modified = true;}}return modified;}
- modcount,是一个体系化的事情,是保证遍历的快速失败。需要保证每个影响正确性的地方都修改到,那么怎么保证呢?根据注释来看,是所有会导致list产生结构性变化的地方都需要修改modcount。然后确定方法中是否需要修改modCount就有根据了。
相关文章:

ArrayList源码学习笔记(3)
时隔两年,重新读ArrayList源码,轻松了很多,以问题的方式记录一下收获 装饰器模式 注释中提到ArrayList本身不是线程安全的,注释如下: * <p><strong>Note that this implementation is not synchronized.&…...

flutter怎么对ReorderableListView中的用于排序的控制手柄进行显示或隐藏
我在使用ReorderableListView创建可排序列表的时候,需要在编辑的时候才显示右侧的控制排序的手柄。研究了半天,配合搜索引擎,才找到正确的方案。 答案很简单,就是在它的属性当中有一个叫做:buildDefaultDragHandles的…...

python 1200例——【9】斐波那契数列
文章目录 定义求解方法1. 递归方法2. 循环方法3. 动态规划方法4. 矩阵方法总结:定义 斐波那契数列(Fibonacci sequence)是一个在自然世界中经常出现的数学序列。它是由0和1开始,然后的每个数字都是前两个数字的和。因此,斐波那契数列的前几个数字是:0, 1, 1, 2, 3, 5, 8…...

JavaScript读写T5557卡源码
本示例使用发卡器: https://item.taobao.com/item.htm?spma1z10.5-c-s.w4002-21818769070.13.48ce6f89XlQ9Vf&id675212889085 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-t…...

【数据结构】LRU缓存的简单模拟实现(leetcode力扣146LRU缓存)
文章目录 一、定义二、LRU模拟实现二、代码实现 一、定义 LRU是Least Recently Used的缩写,意思是最近最少使用,它是一种Cache替换算法。 Cache的容量有限,因此当Cache的容量用完后,而又有新的内容需要添加进来时, 就…...

基于电商场景的高并发RocketMQ实战-Commitlog基于内存的高并发写入优化、基于JVM offheap的内存读写分离机制
🌈🌈🌈🌈🌈🌈🌈🌈 【11来了】文章导读地址:点击查看文章导读! 🍁🍁🍁🍁🍁🍁dz…...

工具系列:TensorFlow决策森林_(3)使用dtreeviz可视化
文章目录 介绍设置安装 TF-DF 和 dtreeviz导入库 可视化分类树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随机森林分类器显示决策树检查叶节点统计信息决策树如何对实例进行分类特征空间划分 可视化回归树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随…...

【算法学习】斐波那契数列模型-动态规划
前言 我在算法学习过程中,针对斐波那契数列模型的动态规划的例题进行了一个整理,并且根据标准且可靠一点的动态规划解题思路进行求解类似的动归问题,来达到学习和今后复习的必要。 所谓的斐波那契数列模型,即当前状态的值等于前两…...

ES的安装和RestClient的操作
目录 初识elasticsearch 什么是elasticsearch elasticsearch的发展 Lucene的优缺点 elasticsearch的优势 倒排索引 es与mysql的概念对比 文档 索引 概念对比 架构 安装es 安装kibana 安装ik分词器 分词器 安装ik分词器 ik分词器的拓展和停用词典 操作索引库…...

访问者模式(Visitor)
访问者模式(Visitor Pattern)是一种将算法与对象结构分离的行为型设计模式。这种模式主要用于对一个由许多不同类型的对象构成的复杂对象结构(如组合结构)进行操作,而不需要对这些对象的类进行修改。 访问者模式涉及以下几个角色: 访问者(Visitor):为每一个具体元素类…...

ATTCK红队评估一
一、环境搭建 主机 ip地址 win7外网服务器(两张网卡) 外网:192.168.92.135 内网:192.168.52.143 server2003域成员主机 内网:192.168.52.141 server2008域空主机 内网:192.168.52.138 kali攻击机 …...

W5500-EVB-Pico评估版介绍
文章目录 1 概述2 板载资源2.1 硬件规格2.2 硬件规格2.3 工作条件 3 参考资料3.2 原理图3.3 尺寸图 (单位 : mm)3.4 参考例程 4 硬件协议栈优势 1 概述 W5500-EVB-Pico是基于树莓派RP2040和完全硬连线TCP/IP控制器W5500的微控制器开发板-基本上与树莓派Pico板相同,但…...

单聊和群聊
TCP协议单聊 服务端: import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Vec…...

Swift 检测 iCloud状态
Show me the code: func isICloudContainerAvailable() -> Bool {if let _ FileManager.default.ubiquityIdentityToken {return true} else {return false} }推荐一下刚上线的 App 熊猫小账本,里面有用到这篇博客讲的内容 熊猫小账本 一个简洁的记账 App&…...

使用Windi CSS(基于vue-cli)
1、先创建vue项目 利用脚手架vue-cli创建,根据需求设置vue版本、babel等,无特别要求直接用默认的vue2或vue3就行 vue create 项目名 2、运行vue项目,利用vue-cli安装Windi CSS 官网指导:Vue CLI 集成 | Windi CSS 我的经历&a…...

操作无法完成(错误 0x000006ba),Windows 11 PDF打印机无法使用解决办法
操作无法完成(错误 0x000006ba),Windows 11 PDF打印机无法使用解决办法 解决方式一 先重启一次电脑,看看是否可以解决问题。 解决方式二 重新启动 Printer Spooler 服务...

Settings中电池选项-Android13
Settings中电池选项-Android13 1、设置中界面2、电池计算2.1 充电时间计算2.1.1 BatteryUsageStats获取2.1.2 BatteryStatsImpl计算 2.2 电池剩余使用时间2.2.1 Estimate获取2.2.2 BatteryStatsImpl计算 3、电池信息来源4、命令模拟* 日志 [电池]Android 9.0 电池未充电与充电字…...

解密 Java ForEach 提前终止问题
目录 前言:场景复现分析与解决方案解决方案详解总结 前言: 你是否曾在使用 Java 8 的 forEach 迭代集合时遇到过提前终止循环的问题?在这篇博客中,我们将深入探讨这一问题,并提供多种解决方案。通过场景复现、分析源码…...

7_js_dom编程入门1
Objective(本课目标) 掌握获取页面元素的常用方法 掌握事件触发案例 能够区分innerText和innerHTML的区别 综合案例训练 1 DOM 介绍 1.1 什么是DOM 文档对象模型(Document Object Model,简称DOM),是 …...

使用 Elasticsearch 检测抄袭 (一)
作者:Priscilla Parodi 抄袭可以是直接的,涉及复制部分或全部内容,也可以是释义的,即通过更改一些单词或短语来重新表述作者的作品。 灵感和释义之间是有区别的。 即使你得出类似的结论,也可以阅读内容,获得…...

STM32 cubeMX 直流电机控制风扇转动
本文使用的是 HAL 库。 文章目录 前言一、直流电机介绍二、直流电机原理图三、直流电机控制方法四、STM32CubeMX 配置直流电机五、代码编写总结 前言 实验开发板:STM32F051K8。所需软件:keil5 , cubeMX 。实验目的:了解 直流电机…...

我在 VSCode 插件里接入了 ChatGPT,解决了Bug无法定位的难题
作为一名软件开发者,我时常面临着代码中Bug的定位和解决问题。这个过程往往既费时又充满挑战。然而,最近我在我的VSCode插件中接入了ChatGPT,这个决定彻底改变了我处理Bug的方式。 Bug:开发者的噩梦 在开发过程中,遇…...

学Java的第四天
一、switch语句 switch (表达式) { case 1: 语句体1; break; case 2: 语句体2; break; ... default: 语句体n1; break; } 首先计算表达式的值,然后和case 比较,有对应的值就执行对应的语句,遇到 break 就结束。 最后如果所有的cas…...

[内功修炼]函数栈帧的创建与销毁
文章目录 1:什么是函数栈帧2:理解函数栈帧能解决什么问题呢3:函数栈帧的创建与销毁的解析3.1:什么是栈3.2:认识相关寄存器与汇编指令相关寄存器相关汇编指令 3.3 解析函数栈帧的创建和销毁3.3.1 预备知识3.3.2 详细解析一:调用main函数,为main函数开辟函数栈帧First:push前push…...

【深度学习-目标检测】03 - Faster R-CNN 论文学习与总结
论文地址:Faster R-CNN: Towards Real-Time ObjectDetection with Region Proposal Networks 论文学习 1. 摘要与引言 研究背景与挑战:当前最先进的目标检测网络依赖于 区域提议(Region Proposals)来假设目标的位置,…...

oracle11体系结构二-存储结构
数据区: 数据区(数据扩展区)由一组连续的oracle数据块所构成的存储结构,一个或多个数据块组成一个数据区,一个或多个数据区组成一个段。当段中所有空间被使用完后,oracle系统将自动为该段分配一个新的数据…...

如何通过内网穿透实现远程访问本地Linux SVN服务
文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…...

网页乱码问题(edge浏览器)
网页乱码问题(edge) 文章目录 网页乱码问题(edge)前言一、网页乱码问题1.是什么:(描述)2.解决方法:(针对edge浏览器)(1)下载charset插…...

泛微OA xmlrpcServlet接口任意文件读取漏洞(CNVD-2022-43245)
CNVD-2022-43245 泛微e-cology XmlRpcServlet接口处存在任意文件读取漏洞,攻击者可利用漏洞获取敏感信息。 1.漏洞级别 中危 2.影响范围 e-office < 9.5 202201133.漏洞搜索 fofa 搜索 app"泛微-OA(e-cology)"4.漏洞复现 …...

MATLAB ga函数的使用方法
一、ga句法结构 x ga(fitnessfcn,nvars) x ga(fitnessfcn,nvars,A,b) x ga(fitnessfcn,nvars,A,b,Aeq,beq) x ga(fitnessfcn,nvars,A,b,Aeq,beg,IB,UB) x ga(fitnessfcn,nvars,A,b,Aeq,beq,LB,UB,nonlcon) x ga(fitnessfcn,nvars,A,b,Aeq,beq,LB,UB,nonlcon,options) x …...