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

    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()一致。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

百度地图1

地图的基本操作 百度地图3.0文档 百度地图3.0实例中心 设置地图 centerAndZoom(center: Point, zoom: Number)设初始化地图,center类型为Point时&#xff0c;zoom必须赋值&#xff0c;范围3-19级&#xff0c; // 百度地图API功能var map new BMap.Map("map"); //…

CentOS8搭载正反向解析dns服务器

1.介绍&#xff08;是什么&#xff09; DNS&#xff08;Domain Name System&#xff09;&#xff0c;即域名系统&#xff0c;是一个将域名和 IP 地址相互映射的分布式数据库&#xff0c;它可以将用户输入的域名转换成对应的 IP 地址。DNS 由多个服务器组成&#xff0c;分为多个…

企业想要搭建一个虚拟展厅需要多少钱?

企业搭建虚拟展厅的费用会根据多种因素有所不同&#xff0c;主要包括展厅的类型、规模、功能需求、技术复杂度以及服务商的定价策略等。以下是关于虚拟展厅搭建费用的分点说明和归纳&#xff1a; 一、展厅类型&#xff1a; 1、全景实拍展厅&#xff1a; 利用VR全景拍摄技术还…

结构体中内存的对齐

前言 学C的同学应该知道~ 想精通C语言就不得不面对—指针与内存 续上次指针进阶&#xff0c;这一章我来聊一聊C语言内存对齐的问题 学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的&#x1f601; 思考 #include<stdio.h> typedef struct s1 {char a;char …

【Python】 如何获取 Python 函数的名称作为字符串?

基本原理 在 Python 中&#xff0c;获取函数名称是一个简单但非常有用的技巧&#xff0c;尤其是当你需要动态地引用函数或者在日志、调试中需要函数名称时。Python 提供了几种方法来获取函数的名称。 方法一&#xff1a;使用 __name__ 属性 每个函数对象都有一个 __name__ 属…

【Unity】使用Jenkins实现远程Unity打包

前言 很多时候&#xff0c;我们需要自动打包&#xff0c;比如下班了&#xff0c;我要出一个包明天早上用。比如每天夜里12点&#xff0c;我需要定时出一个稳定包。 这个时候就需要Jenkins了。 1.安装环境 安装 jenkins 之前&#xff0c;需要安装Java 。Java下载网站 ①下载…

校园交友|基于SprinBoot+vue的校园交友网站(源码+数据库+文档)

校园交友网站 目录 基于SprinBootvue的校园交友网站 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台功能模块 5.2.1管理员功能模块 5.2.2用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#x…

音视频开发9 FFmpeg 解复用相关整体说明,重要API说明

一&#xff0c;播放器框架 二 常用音视频术语 容器&#xff0f;文件&#xff08;Conainer/File&#xff09;&#xff1a; 即特定格式的多媒体文件&#xff0c; 比如mp4、flv、mkv等。 媒体流&#xff08;Stream&#xff09;&#xff1a; 表示时间轴上的一段连续数据&#xff0…

【技术实操】银河高级服务器操作系统实例分享,数据库日志文件属主不对问题分析

1. 问题现象描述 2023 年 06 月 30 日在迁移数据库过程中&#xff0c;遇到数据库 crash 的缺陷&#xff0c;原因如下&#xff1a;在数据库启动时候生成的一组临时文件中&#xff0c;有 owner 为 root 的文件&#xff0c; 文件权限默认为 640&#xff0c; 当数据库需要使用的时…

C++系列——————类和对象(上)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、面向对象的三大特征二、类的引入2.1类的定义 三.类的访问限定符3.1访问限定符的介绍3.2.访问限定符的使用 四、类的作用域五、类的实例化六、类对象模型6.1…

惠海 H6251L 降压恒压芯片IC 48V 60V 100V 150V 200V 降3.3V 5V 12V 5A大电流 低功耗,动态响应优异

H6251L是一款多样化的高压降压开关控制器&#xff0c;它具备许多引人注目的特性和优势&#xff0c;使其在多个领域都有许多的应用。以下是对H6251L的详细分析&#xff1a; 首先&#xff0c;H6251L具有宽压8V-200V的输入范围&#xff0c;这意味着它可以在电压环境下稳定工作&am…

【康耐视国产案例】智能AI相机联合OSARO为Zenni眼镜实现订单履约自动化

在电商潮流下&#xff0c;Zenni眼镜作为全球领先的在线眼镜零售商&#xff0c;每年销售超过600万副眼镜&#xff0c;却面临着一个独特而复杂的问题——需要通过扫描眼镜盒内的条形码来处理订单。传统手动处理已经到达流程瓶颈&#xff0c;急需一种更加自动化、可扩展的方法。为…

STM32 HAL库USART的接收数据方法实现(STM32Cube_FW_F1_V1.8.5)

目录 概述 1 使用STM32Cube生成项目 1.1 软件版本信息 1.2 配置串口相关参数 1.3 生成工程 2 问题描述 3 解决问题 3.1 修改代码 3.2 编写新的回调函数 4 测试 概述 本文主要介绍STM32 HAL库USART的接收数据方法实现&#xff0c;笔者使用的HAL库为STM32Cube_FW_F1_V1.…

Leetcode刷题笔记6

34. 在排序数组中查找元素的第一个和最后一个位置 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力查找 [1, 2, 3, 3, 3, 4, 5] t 3 从前往后扫描暴力查找&#xff0c;最坏情况下O(N) 优化 利用数组有序的…

【动态规划 组合数学 放球问题】2338. 统计理想数组的数目

本文涉及知识点 动态规划汇总 组合数学汇总 【组合数学 隔板法 容斥原理】放球问题 本题同解 【动态规划】【前缀和】【分组】2338. 统计理想数组的数目 LeetCode2338. 统计理想数组的数目 给你两个整数 n 和 maxValue &#xff0c;用于描述一个 理想数组 。 对于下标从 0…

Unity中模拟生成正态分布的一种方式

using System; using System.Collections; using System.Collections.Generic; using Unity.Mathematics; using UnityEngine;public class MathFunction : MonoBehaviour {private void Start(){//key 范围 0-99 表示 0% 到 99%Dictionary<int,uint> m new Dictionary&…

CSS绘制圆弧

css绘制如图的圆弧&#xff1a; 这种矩形弧形的效果中&#xff0c;弧形的效果一般是由一条曲线拉伸出来的&#xff0c;这条曲线往往是属于一个椭圆的&#xff0c;所以可以绘制一个椭圆&#xff0c;截取部分可视区域实现效果。 <style> .wrapper{width: 400px;height: 60…

Hive原理及、部署和以及使用(超详细)

Hive的安装配置、初始化元数据、启动 1、解压hive到指定目录/usr/local/src 改名&#xff0c;将mysql的驱动包拷贝到hive的lib目录下 2、环境变量 1&#xff09; vi /etc/profile export HIVE_HOME/usr/local/src/hive export PATH P A T H : PATH: PATH:HIVE_HOME/bin echo…

20 厂商文档学习资料查询

01 厂商介绍 新华三&#xff08;H3C&#xff09; 新华三是一家专注于IT基础设施产品和解决方案的公司&#xff0c;提供从网络设备到数据中心解决方案的全套服务。它是中国领先的网络解决方案供应商之一&#xff0c;业务涵盖企业网、数据中心、云计算等多个领域。 华为&#x…

Java排序算法汇总篇,八种排序算法

排序算法汇总: Java排序算法(一)&#xff1a;冒泡排序 Java排序算法(二)&#xff1a;选择排序 Java排序算法(三)&#xff1a;插入排序 Java排序算法(四)&#xff1a;快速排序 Java排序算法(五)&#xff1a;归并排序 Java排序算法(六)&#xff1a;希尔排序 Java排序算法(…