【Java容器(jdk17)】ArrayList深入源码,就是这么简单

news2024/9/29 13:32:21

ArrayList深入源码

  • 一、ArrayList源码解析
    • 1. MIXIN 的混入
    • 2. 属性说明
    • 3. 构造方法
    • 4. 其他方法(核心)
      • iterator 和 listIterator 方法
      • add方法
      • remove 方法
      • sort方法
      • 其他
  • 二、ArrayList 为什么是线程不安全的?体现哪些方面呢?
  • 三、ArrayList 细节汇总

前言:
个人觉得看源代码会增进不少知识,一直都是看别人写的博客中的代码片段,没自己静下心来去看过,接下来体验体验源码的快乐。

一、ArrayList源码解析

在这里插入图片描述

对 ArrayList 相应关系有了大致的了解后,咱由外到里依次深入。

1. MIXIN 的混入

ArrayList 利用 MIXIN 的思想,实现了多继承。

说明其实现的接口:

  1. Serializable接口:使得ArrayList 支持序列化和反序列化。
  2. RandomAccess接口:该接口是一个标记接口,意在标明ArrayList 具备快速随机访问的能力,使用for 会比使用 迭代器(iterator)访问速度要快。LinkedList 那边即不具备这种能力,所以不存在这种标记(原因是因为LinkedList 底层是链表,访问都是从根到尾的,所以它使用迭代器会更快)。
  3. Cloneable接口:也是一个标记接口,实现了它便可以去重写Object 下的clone 方法,利于对象进行创建副本。(注意:是ArrayList 实现了Cloneable接口,当利用多态向上转型为List 时,是不可以使用的。

下面是 ArrayList 内部重写的 clone 方法的代码。

/**
     * Returns a shallow copy of this {@code ArrayList} instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this {@code ArrayList} instance
     */
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

emmmm…这里我不知道返回值的数据类型不直接为 ArrayList,一般我去重写的话就会直接。。。

2. 属性说明

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 构造方法

ArrayList 有三个构造方法,俩有参,一无参的。

在这里插入图片描述

在这里插入图片描述

第三个描述的那个构造方法如何使用呢 ?

由于Arrays.asList() 得到的集合固定大小的,是由Arrays内部类所实例化的,是没有 clone(),add(),remove(),clear()等这样的动态操作的,但如果想要使用这种动态操作怎么办呢?

那咱就可以利用这个构造方法,看代码更清晰:

		String[] s = {"xx","yy"};
        //List<String> xxx = Arrays.asList(s);
        //xxx.add("mm"); 
        /*这里运行最后是会报异常的,
        这是因为Arrays 里面有个ArrayList 的内部类,
        它没有重写add和remove等方法。
        但没运行是不会爆红的,虽然没有重写那些方法,但该内部类继承了
        AbstractList,这个类里面这些方法不是抽象的...*/

        List<String> list = new ArrayList<>(Arrays.asList(s));
        list.add("mm");
        list.forEach(System.out::println);// 正常输出

在这里插入图片描述

4. 其他方法(核心)

先不说方法,先说说类里面实现的Iterator接口和它的子接口,ListIterator接口。(虽然ArrayList 实例对象用迭代器的话比较少,但是量变质不变,LinkedList 可以用啊)。

iterator 和 listIterator 方法

在这里插入图片描述

  • 看看Iterator 接口的实现类 Itr 内部吧:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 再来看看 ListIterator 接口实现类 ListItr(继承了Itr) 的内部吧:

在这里插入图片描述
在这里插入图片描述

这里继承,所以forEachRemaining方法也是可以使用的。

有了 listIterator() , 不会还有人用 iterator() 吧。注意ListIterator 只在List 集合中出现了哦,也就是 Vector、ArrayList、LinkedList、Stack这样的。

也可以看看 JAVA中ListIterator和Iterator详解与辨析 这篇博客对其的一些解释。

add方法

add 对外提供的方法有俩,add(E e)add(int index, E e)。它俩有公共的点是,判断类内定义的elementData数组长度是否和元素size(个数)相匹配,是否需要扩容。
也就是说它们俩有一个共同的方法,让elementData扩容。咋括滴勒,咱来看看这个grow方法内部。

在这里插入图片描述
咱看别人博客都说是1.5倍扩容的,但是是怎么个扩容呢?下面看源码分析分析。

在这里插入图片描述

通过调用 ArraysSupport类中的newLength方法,我们获得newCapacity后,通过Arrays.copyOf完成扩容。

  • 先来看看ArraysSupport类中的newLength方法。(1.5倍的由来)

在这里插入图片描述

  • 再来看看Arrays.copyOf方法调用吧:

在这里插入图片描述
它内部用的是System.arraycopy这个方法。这是核心啊,我觉得这也是ArrayList 性能要比较好的关键。这玩意将数据复制给一个副本然后返回给elementData数组。arraycopy 是本地(native)方法。它强在它是浅拷贝,它是直接拷贝所存放的地址,而不是像深拷贝那样重新分配内存。

有关浅拷贝和深拷贝,可以看看这篇《浅拷贝和深拷贝》,或者我写的这篇《clone方法》。

了解完如何扩容之后,再来看看俩方法的具体实现:

  • add(E e)

在这里插入图片描述

  • add(int index,E e)

在这里插入图片描述

remove 方法

remove 方法也有两种对外提供,remove(int index),remove(Object obj)

它们都是根据索引去调用内部的 fastRemove(Object[] es, int i)方法去进行移除。也是调用System下面的arraycopy方法,然后把那个设置为空(null),让GC回收。

咱先来看看 fastRemove 方法的实现吧:

在这里插入图片描述

  • remove(int index)

在这里插入图片描述

  • remove(Object obj)

在这里插入图片描述

有关 mark 标记的使用可以看这篇博客《mark标号》。

从代码可以看出,不管传入的参数是空还是非空,都会对 elementData 进行操作进行删除。

sort方法

jdk1.8 后,List接口就引入了sort 这个默认方法。

  • List 中的 sort 方法:

在这里插入图片描述

  • ArrayLIst 重写的 sort 方法(重写的原因很简单,ArrayList内部本就是动态数组所构的,用迭代器去重写对元素进行设置纯属是多余):

在这里插入图片描述
及其舒适简单。

可以直接用LIst集合中的sort了,其实调用Collections 工具类中的sort 方法,最后还是会回到List 集合中,还不如直接使用呢。

其他

还有一些常用的 方法,比如:

  • set(int index,E element)
  • isEmpty()
  • get(int index)
  • indexOf(Object)
  • lastIndexOf(Object)
  • clear()
  • toArray()
  • contains()
  • trimToSize() 还是通过Arrays.copyOf 将数组长度变成和数组元素个数(size)一致,可以减少空间的损失。

理解了 ArrayList 的本质,这些方法的实现其实自己想也想的出来。

二、ArrayList 为什么是线程不安全的?体现哪些方面呢?

可以看看这篇博客写的几点线程不安全的情况以及其测试。

《ArrayList为什么线程不安全 线程不安全体现在哪些方面 源码角度分析其具体原因》

三、ArrayList 细节汇总

  • ArrayList 是基于动态数组实现的,当进行插入或删除操作的时候,都会进行数组的拷贝复制。
  • ArrayList 它很多地方是分步进行操作的,**而且内部元素也是可以为 null 的。**它不是线程安全的。
  • ArrayList 删除元素时,只会改变元素的个数(size),而不会改变容量(elementData.length),如果想要更改,可以调用trimToSize()方法,它会给你改成和元素个数一样的值。

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

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

相关文章

(day12) 自学Java——集合进阶(双列集合)

目录 1.双列集合特点 Map遍历三种方式 2.HashMap 3.LinkedHashMap 4.TreeMap 5.源码解析 6.可变参数(形参个数可变) 7.Collections 8.综合练习 1.双列集合特点 ①双列集合一次需要存一对数据&#xff0c;分别为键和值 ②键不能重复&#xff0c;值可以重复 ③键和值是一…

全志H616——用C语言的形式操作数据库

sqlite3_open(const char *filename, sqlite3 **ppDb)该例程打开一个指向 SQLite 数据库文件的连接&#xff0c;返回一个用于其他 SQLite 程序的数据库连接对象。sqlite3_close(sqlite3*)该例程关闭之前调用 sqlite3_open() 打开的数据库连接。所有与连接相关的语句都应在连接关…

【Linux】环境变量本地变量

文章目录环境变量基本概念常见环境变量和环境变量相关的命令为什么带./运行我们的可执行程序本地变量环境变量的组织方式环境变量具有全局属性环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如&#xff1a;我们…

gRPC的简单应用

gRPC的简单应用 gRPC是由开发的一个高性能、通用的开源RPC框架&#xff0c;主要面向移动应用开发且基于HTTP/2协议标准而设计&#xff0c;同时支持大多数流行的编程语言。 官网&#xff1a;https://grpc.io/ 安装protoc 工具 https://protobuf.dev/ 安装Go插件 旧版本直接…

学习HandlerThread

HandlerThread是一个扩展了Thread的类。也就意味着它和普通的Thread类的调用没有什么区别&#xff0c;仍然要调用start()。 如上图所示&#xff0c;扩展后的HandlerThread类有一个Looper和Handler。 关于这一块的知识可以参考一下《关于Handler我们应该知道的知识》 HandlerTh…

普冉PY32系列(五) 使用JLink RTT代替串口输出日志

目录 普冉PY32系列(一) PY32F0系列32位Cortex M0 MCU简介普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单普冉PY32系列(四) PY32F002A/003/030的时钟设置普冉PY32系列(五) 使用JLink RTT代替串口输出日志 JLink …

Python-第五天 Python函数

Python-第五天 Python函数一、函数介绍1. 什么事函数二、函数的定义1.函数的定义&#xff1a;2.案例三、函数的参数1.函数的传入参数2.案例升级四、函数的返回值1.什么是返回值2.返回值的语法3.None类型4.None类型的应用场景五、函数说明文档1.函数的说明文档2.在PyCharm中查看…

脑机接口协议V1.0

脑机接口&#xff0c;有时也称作“大脑端口”direct neural interface或者“脑机融合感知”brain-machine interface&#xff0c;它是在人或动物脑&#xff08;或者脑细胞的培养物&#xff09;与外部设备间建立的直接连接通路。在单向脑机接口的情况下&#xff0c;计算机或者接…

leaflet显示高程

很多地图软件都能随鼠标移动动态显示高程。这里介绍一种方法&#xff0c;我所得出的。1 下载高程数据一般有12.5m数据下载&#xff0c;可惜精度根本不够&#xff0c;比如mapbox的免费在线的&#xff0c;或者91卫图提供百度网盘打包下载的&#xff0c;没法用&#xff0c;差距太大…

记录robosense RS-LIDAR-16使用过程3

一、wireshark抓包保存pcap文件并解析ubuntu18安装wireshark&#xff0c;参考下面csdn教程&#xff0c;官网教程我看的一脸蒙&#xff08;可能英语太差&#xff09;https://blog.csdn.net/weixin_46048542/article/details/121730448?spm1001.2101.3001.6650.2&utm_medium…

秒杀项目之服务调用分布式session

目录 nginx动静分离 服务调用 创建配置zmall-cart购物车模块 创建配置zmall-order订单模块 服务调用 spring session实战 什么是Spring Session 为什么要使用Spring Session 错误案例展示 配置spring-session 二级域名问题 用户登录 nginx动静分离 第1步&#xff…

如何用演示程序检测K100|K720|K750电动发卡读写一体机性能

K100|K720|K750电动发卡读写一体机采用工业级设 计&#xff0c;表面烤漆处理&#xff0c;具有良好的耐磨耐腐蚀性。适应各种高、低温&#xff0c; 多灰尘等 恶劣环境。其发卡原理为拟人型摩擦式发卡&#xff0c;对各类变形卡有非常好的适应性。 CNC的精度保证卡距的绝对一致性、…

Filter过滤器完成验证代码的封装

Filter过滤器完成验证代码的封装filter是什么1 使用filter2 filter配置到项目中验证用户权限是需要反复使用的代码块&#xff0c;把他封装到filter中&#xff0c;减少代码冗余filter是什么 init()方法&#xff1a;初始化方法&#xff0c;在创建Filter后立即调用。可用于完成初始…

刚刚,体验了一把Bing chat很爽

文章目录刚刚&#xff0c;体验了一把Bing chat很爽你能做啥&#xff1f;与chatgpt有什么不同&#xff1f;以下是Bingchat的 10个新功能1⃣️在网上搜索结果2⃣️摘要链接3⃣️对话助手4⃣️向您发送实际信息&#xff0c;正确的链接5⃣️在单个查询中执行多个搜索6⃣️玩冒险游戏…

内网渗透(十八)之Windows协议认证和密码抓取-本地认证(NTML哈希和LM哈希)

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

【Web测试】各类web控件测试点汇总,软测人必备

一 、界面检查 进入一个页面测试&#xff0c;首先是检查title&#xff0c;页面排版&#xff0c;字段等&#xff0c;而不是马上进入文本框校验 1、页面名称title是否正确 2、当前位置是否可见 您的位置&#xff1a;xxx>xxxx 3、文字格式统一性 4、排版是否整齐 5、列表项显示…

leetcode: 3Sum

leetcode: 3Sum1. 题目描述2. 思考3. 解题3. 总结1. 题目描述 Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i ! j, i ! k, and j ! k, and nums[i] nums[j] nums[k] 0. Notice that the solution set must not contain …

爬虫Python入门好学吗?学什么?

爬虫Python入门好学吗&#xff1f;学爬虫需要具备一定的基础&#xff0c;有编程基础学Python爬虫更容易学。但要多看多练&#xff0c;有自己的逻辑想法。用Python达到自己的学习目的才算有价值。如果是入门学习了解&#xff0c;开始学习不难&#xff0c;但深入学习有难度&#…

2022年12月电子学会Python等级考试试卷(一级)答案解析

青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;一级&#xff09; 一、单选题(共25题&#xff0c;共50分) 1. 关于Python语言的注释&#xff0c;以下选项中描述错误的是&#xff1f;&#xff08; &#xff09; A. Python语言有两种注释方式&…

JavaEE16-Spring事务和事务传播机制

目录 1.为什么需要事务&#xff1f; 2.MySQL中事务的使用 3.Spring中事务的实现 3.1.编程式事务&#xff08;手动写代码操作事务&#xff09; 3.2.声明式事务&#xff08;利用注解自动开启和提交事务&#xff09;(使用为主) 3.2.1.Transactional作用范围 3.2.2.Transact…