Java集合-List(Collection子接口)及其子类(ArrayList、Vector、LinkedList)

news2024/11/24 20:36:28
    List接口是 Collection接口的子接口。
1、List集合类中数据有序, 即添加顺序和取出顺序有序,而且可以重复。
2、List集合类中每个元素都有其对应的顺序索引,即支持索引。例,list.get(2);取第三个元素。
3、实现类有很多,介绍ArrayList、Vector、LinkedList三种。
常用方法:
    其方法相当于在父接口Collection中加入了索引,可以根据索引进行增删改查。
1、void add(int index, Object ele)
        将指定的元素插入此列表中的指定位置(可选操作)。
        该位置之后的元素则依次往后移一位。
2、boolean addAll(int index, Collection eles)
        从index位置开始,将eles中的所有元素添加进来。
3、Object get(int index)
        获取index位置的元素。
4、int indexOf(Object obj)
        返回obj元素在集合中首次出现的位置。
5、int lastIndexOf(Object obj)
        返回obj元素在集合中最后出现的位置。
6、Object remove(int index)
        移除指定index位置的元素,并返回该元素。
7、Object set(int index, Object ele)
        设置指定index位置的元素为ele,相当于用ele 替换原来元素。注意,index位置必须有元素,否则抛出异常。
8、List subList(int formIndex, int toIndex)
        返回从 formIndex 到 toIndex 的子集合。
遍历方式:
    因为其是Collection的子接口,所以方法1和方法2与Collection一致。
    但是其可以有索引,因此通过索引访问,因此可以通过方法3,普通for循环通过索引访问。
1、使用迭代器Iterator
2、使用增强for
3、使用普通for

一、ArrayList

1、ArrayList可以添加null,并且可以添加多个。
2、ArrayList是由数组来实现数据存储的。
3、ArrayList基本等同于Vector,除了ArrayList是线程不安全的,多线程不建议使用ArrayList。

底层源码:

1、ArrayList 中维护了一个 Object 类型的数组 elementData[].
transient关键字:即被其修饰的属性不会被序列化。
    
2、创建ArrayList对象逻辑分析。
        如果使用无参构造器,则elementData[]的容量为0;
            第一次添加则扩容为10,如果需要再次扩容,则扩容为原来的1.5倍。
        如果使用指定大小的构造器,则elementData[]的容量为指定大小,
            如果需要扩容,则直接扩容为1.5倍。
①使用无参构造器创建对象:
    给elementData赋初值 DEFAULTCAPACITY_EMPTY_ELEMENTDATA ,即第二张图:空数组。
指定大小创建对象:(需要看完无参构造创建对象的四个步骤再看)
    即使用有参构造器ArrayList(int initialCapacity),
        如果给定的值大于0,则直接给elementData赋值一个对应大小的数组
        如果等于0,则跟使用无参一样。
        否则抛出异常。
所以,只要使用无参构造器,所有的ArrayList的elementData属性都是同一个:
    
②第一次执行add()
    
    先使用ensureCapacityInternal()函数判断容量够不够
    然后在进行添加元素。
③确定容量是否足够
    调用ensureCapacityInternal()函数,
        调用calculateCapacity()函数返回一个最小容量。
        得到最小容量后调用ensureExplicitCapacity()判断是否需要扩容。
详情如下:
ensureCapacityInternal()函数:
            
calculateCapacity()函数:
    先确定elementData[]是否是最开始的空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,
    如果是,就返回 DEFAULT_CAPACITY 和 minCapacity 中较大的那个,
        其中DEFAULT_CAPACITY初始值为10.(定义如下图二)
    否则直接返回minCapacity。
    
ensureExplicitCapacity():
        第一步modCount++,是记录当前集合被操作次数。
        第二步判断最小容量 - 当前容量是否大于0,
            如果>0,说明实际容量比最小容量要小,则容量不够了,需要进行扩容。
            则调用grow()方法去扩容。
    
④使用grow()去扩容
    先获取newCapacity的值,即新数组的容量,
    然后使用Arrays.copyOf()函数获得新数组。
详细过程:
    oldCapacity接收未扩容前的容量;
    newCapacity的值为oldCapacity的1.5倍,即 newCapacity = oldCapacity + (oldCapacity >> 1);
    因为第一次old为0,所以new也为0,因此需要判断一下:
        当new - min < 0时,即新的容量小于最小容量,则直接将min赋值给new
    如果新的容量比最大容量大,则进行hugeCapacity()方法
        最大容量MAX_ARRAY_SIZE定义在图二
    最后使用 Arrays.copyOf()函数获得新数组。
    
    

二、Vector

1、vector也是使用数组来实现存储的。
2、vector是线程同步的,即线程安全。

1、定义

    
其在底层也维护了一个Object类型的数组,用来存储数据:
    可见没有transient关键字,即可以序列化。
    
其线程安全:
    其方法都有synchronized关键字修饰。
    

2、与ArrayList比较:

    

3、创建对象逻辑分析(源码)

①无参
    第一步:调用自身的有参构造器,默认赋值为10;
    
②add()
     add()方法和ArrayList类似,只是将modCount++放在了最开始,
    然后执行ensureCapacityHelper()方法确定容量是否足够。
    如果不够则执行grow()方法
    够则直接添加数据。
详细:
add():
   
ensureCapacityHelper():
    
grow():
    可见与ArrayList不同:int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
    先判断属性capacityIncrement是否大于0,若不大于0,则new = old +old,即扩容为2倍。
    属性capacityIncrement作用在有参构造中使用,其默认值为0;
  
③有参
    如下如,Vector的三个构造器,源码如下:
    可见其为相互调用,第三个则为最终构造器。
        第一个参数为初始容量
        第二个参数最终赋给capacityIncrement属性,作用为说明每次容量满时,增加多少,如上图grow()函数。
        即不给此变量赋值则增长为2倍。
      
    
   
    

三、LinkedList

1、底层实现了双向链表和双端队列。
2、可以添加任意元素,包括null。
3、线程不安全,没有实现同步。

1、底层操作机制:

    1、底层维护了一个双向链表
    2、维护两个属性first和last,分别指向首节点和尾节点。
        
    3、每个节点(Node对象),里面维护了prev、next和item三个属性,分别是前驱,后驱和值。
        注意Node为LinkedList的内部类。
        
    4、因此LinkedList元素的删除添加不是通过数组完成,效率更高。
            即不用新建数组,然后复制原数组到救数组。

2、与ArrayList对比

3、源码分析:

1、new():创建对象
①无参:
    可见无参构造器什么也不做。
    即仅仅做一个初始化。
        其中first = null;  last = null;  size = 0;
    
②有参:
    有参则先创建一个无参的,然后向里面添加对象。
2、add():增加对象
    此处介绍没有index参数的增加,即向链表最后添加。
    首先执行add()方法
    然后执行linkLast()方法,将元素添加到链表最后。
        
    分析linkLast()方法:
        ①用 l 来存储 last节点
        ②新建一个newNode
            该节点的prev = l,item = e, next = null,即新建节点前驱为插入前的last节点,值为传进来的值,后驱节点为null;
        ③将last节点指向newNode
        ④判断:
            若l = null,即第一次插入(因为只有第一次插入之前,last和first都为null),将first也指向newNode
            若i ≠ null,说明之前依旧插入过,该链表当中已经有元素存在,则将l.next指向newNode,即 l 节点也就是原末节点变成了现末节点的前驱。
        ⑤最后把size加一,把modcount加一。
        
3、remove()删除对象
    此处介绍没有参数的删除,即删除第一个元素。
    首先 调用removeFirst()函数,本函数用来判断是否为null,
    然后执行unlinkFirst()函数删除第一个元素。
    
    可见, removeFirst()函数首先判断first是否为null,为空则抛出异常;
            不为空则调用unlinkFirst()方法,并将f传进去。
    
    首先,将节点f 的item赋给element,用以最后返回
                              next赋给next,用来作为新的first。
              将节点f 的item 和 next均置为null,此时gc会判断其为垃圾,将其回收。
    然后,让first指向next,即指向原来的第二个元素;
    判断:
        如果next = null,即原来就只有一个元素,删除的不仅是第一个元素,也是Last所指向的元素,所以需要将last也指向null。
        如果next ≠ null,说明被移除的结点不是最后一个结点,此时被移除的结点的后一个结点对象持有的prev需要指向null,这样就断开了对移除结点的引用。   
    最后将size减一,将modCount加一。
       
有参数删除remove(int index):
    有参数int的话,会先调用checkElementIndex(index)函数判断对应节点是否存在(通过isElementIndex()判断index是否在0和size之间)
    然后调用unlink(node(index))函数去删除,先使用node(index)函数以此获取到第index位置的节点
    然后使用unlink(Node<E> x)函数删除对应元素。
4、set()修改和get()查询
        这两个函数都是调用node()函数得到对应的节点然后进行操作,与上述remove()一致。

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

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

相关文章

【linux-imx6ull-设备树点灯】

目录 1. 设备树简介1.1 编译-引用1.2 设备树文件结构1.3 设备树节点介绍1.3.1 特殊节点chosen 1.4 节点内容追加 2. 设备树常用OF操作函数2.1 节点寻找类2.2 属性提取类2.3 其它常用类 4. 设备树下LED实验4.1 实验简介4.2 添加LED设备节点4.3 获取设备节点并提取属性4.3.1 获取…

ChatTTS,语气韵律媲美真人的开源TTS模型,文字转语音界的新魁首,对标微软Azure-tts

前两天 2noise 团队开源了ChatTTS项目&#xff0c;并且释出了相关的音色模型权重&#xff0c;效果确实非常惊艳&#xff0c;让人一听难忘&#xff0c;即使摆在微软的商业级项目Azure-tts面前&#xff0c;也是毫不逊色的。 ChatTTS是专门为对话场景设计的文本转语音模型&#x…

iphone内存满了开不了机怎么办?白苹果解决办法分享!

虽然苹果手机在使用时比较顺畅&#xff0c;但是手机用久了&#xff0c;照片、视频等资料累积过多&#xff0c;也难免会导致内存不足&#xff0c;出现无法开机卡在开机界面白苹果的情况。 内存不足导致iPhone白苹果的问题很常见&#xff0c;可以说是苹果最常见的故障之一。接下来…

探索多模态MR图像的脑肿瘤分割任务结构| 文献速递-深度学习肿瘤自动分割

Title 题目 Exploring Task Structure for Brain Tumor Segmentation From Multi Modality MR Images 探索多模态MR图像的脑肿瘤分割任务结构 01 文献速递介绍 脑肿瘤分割旨在从多模态磁共振&#xff08;MR&#xff09;序列中自动分割肿瘤区域&#xff0c;这些序列由先进的…

【Java面试】七、SpringMvc的执行流程、SpringBoot自动装配原理

文章目录 1、SpringMVC的执行流程1.1 视图阶段1.2 前后端分离阶段 2、SpringBoot自动配置原理3、框架常用的注解3.1 Spring的注解3.2 SpringMvc的注解3.3 SpringBoot的注解 4、面试 1、SpringMVC的执行流程 1.1 视图阶段 旧项目中&#xff0c;未前后端分离时&#xff0c;用到…

JVM 指针压缩

运用java内存对齐填充&#xff0c;对java内存进行8字节划分&#xff0c;java对象指针映射到每个划分区域上&#xff0c;使得4个字节&#xff08;32位&#xff09;表示2^32个地址&#xff0c;从而使4个字节指针映射32G内存空间。 1.为什么进行指针压缩&#xff1a; jvm从32位变…

【YUV格式数据】【ffplay】播放或者查看YUV格式图片或文件数据

背景 最近在调试hisi解码功能&#xff0c;需要把h264格式解码成yuv数据&#xff0c;调试的时候需要最后查看下出来的yuv格式数据是否正常&#xff0c;需要用到一些工具软件进行查看。然后就做个总结。 解决方案 方案1&#xff1a;使用ffplay命令播放YUV文件 使用ffplay命令…

vue2 bug 小白求助!!!(未解决,大概是浏览器缓存的问题或者是路由的问题)

我的vue2项目出现了一个超级恶心的bug 具体流程&#xff1a; 页面a点击a标签->到页面b->页面b用户退出刷新页面->点击浏览器的返回按钮返回上一页 返回页面后页面没有刷新导致用户名还显示这 项目中没有用keep-alive缓存 也在设置了key 尝试了window.removeEventLi…

【Linux】线程ID

大致草稿—————————— 思维导图 学习目标 一、线程ID的理解 1.1 引出对tid的理解 我们先来创建一个线程复习一下线程的函数&#xff1a; pthread_t tid; // 创建一个线程 pthread_create(&tid, nullptr, threadrun, (void*)"thread-1"); // 打印出…

惯性动作捕捉与数字人实时交互/运营套装,对高校元宇宙实训室有何作用?

惯性动作捕捉与数字人实时交互/运营套装&#xff0c;可以打破时空限制&#xff0c;通过动捕设备写实数字人软件系统动捕设备系统定制化数字人短视频渲染平台&#xff0c;重塑课程教学方式&#xff0c;开展元宇宙沉浸式体验教学活动和参观交流活动。 写实数字人软件系统内置丰富…

【excel】设置可变下拉菜单(一级联动下拉菜单)

文章目录 【需求】制作动态下拉菜单&#xff0c;显示无重复的“班级”列表【思路】设置辅助列&#xff0c;使用UNIQUE()函数去重&#xff0c;并用FILTER()去掉结果中的“0”【步骤】step1 辅助列step2 设置下拉菜单 【总结】 【需求】制作动态下拉菜单&#xff0c;显示无重复的…

你真的会用收藏夹吗?可道云teamOS收藏夹,竟能缩短多层级文件夹的路径,实现快速访问

在日常工作中&#xff0c;我们时常会面临一个让人头疼的问题&#xff1a;如何在海量的文件和资料中快速找到我们需要的那一份&#xff1f; 尤其是在团队协作中&#xff0c;每个人都在不断地上传、更新文件……导致文件目录层级复杂&#xff0c;搜索也变得繁琐。 这时候&#x…

海外短剧APP/H5 系统开发搭建

目前已经有多个客户用我们搭建的海外短剧系统&#xff0c;在使用中已经取得了较高的收益。目前一个客户打算做日本区域的海外短剧项目&#xff0c;需求已经理清楚了&#xff0c;系统正在搭建中

【iOS】UI学习(二)

UI学习&#xff08;二&#xff09; 进度条和滑动条步进器与分栏控件警告对话框和提示等待器UITextFieldUITextField控件UITextFieldDelegate协议 UIScrollView布局子视图手动布局子视图自动布局子视图 进度条和滑动条 下面通过一个程序来讲解该内容&#xff1a; #import <…

go语言基于Gin集成后台管理系统开发定时任务管理cron/v3好用又好看

系统目前是支持两种定时类型&#xff0c;一种是函数类型&#xff0c;一种是接口类型&#xff0c;来支持多样的业务&#xff1b;时间周期可视化选择&#xff0c;方便设定执行周期。框架UI漂亮&#xff0c;添加管理定时任务设置简单&#xff0c;客户都可以做自己调整执行时间周期…

一维时间序列信号的广义傅里叶族变换(Matlab)

广义傅里叶族变换是一种时频变换方法&#xff0c;傅里叶变换、短时傅里叶变换、S变换和许多小波变换都是其特殊情况&#xff0c;完整代码及子函数如下&#xff0c;很容易读懂&#xff1a; % Run a demo by creating a signal, transforming it, and plotting the results% Cre…

flutter开发实战-下拉刷新继续下拉路由进入活动页面实现

flutter开发实战-下拉刷新继续下拉路由进入活动页面实现 很多应用都有首页通过下拉刷新&#xff0c;继续下拉进入新的活动会场进入方式。在Flutter中&#xff0c;也可以通过pull_to_refresh来实现控制刷新页&#xff0c;继续下拉进入新的活动会场页面 一、引入pull_to_refres…

[Redis]List类型

列表类型来存储多个有序的字符串&#xff0c;a、b、c、d、e 五个元素从左到右组成了一个有序的列表&#xff0c;列表中的每个字符串称为元素&#xff0c;一个列表最多可以存储个元素。在 Redis 中&#xff0c;可以对列表两端插入&#xff08;push&#xff09;和弹出&#xff08…

涂装线体智能化管理:RFID技术的典范案例

涂装线体智能化管理&#xff1a;RFID技术的典范案例 汽车涂装是汽车制造过程中极为关键的一环&#xff0c;涉及多道工序&#xff0c;如预处理、电泳、中涂、面漆等&#xff0c;每一步都需要精确控制以确保车身表面的质量和美观。传统方式下&#xff0c;车辆在不同工位间的流转依…

(CPU/GPU)粒子继承贴图颜色发射

GetRandomInfo节点(复制贴进scratch pad Scripts) Begin Object Class/Script/NiagaraEditor.NiagaraClipboardContent Name"NiagaraClipboardContent_22" ExportPath/Script/NiagaraEditor.NiagaraClipboardContent"/Engine/Transient.NiagaraClipboardConten…