Java中ArrayList、LinkedList和Vector的底层原理

ArrayList

Java中的ArrayList底层原理主要涉及其数据结构、扩容机制、线程安全性以及元素存储和访问方式。以下是对ArrayList底层原理的总结:

数据结构

ArrayList的底层数据结构是一个动态数组。这意味着ArrayList可以根据需要自动增长其容量,从而存储更多的元素。实际上,ArrayList内部维护了一个Object类型的数组,用于存储列表中的元素。

扩容机制

当向ArrayList中添加元素时,如果当前数组的容量不足以容纳新元素,ArrayList会自动进行扩容。扩容操作涉及创建一个新的、容量更大的数组,并将原数组中的元素复制到新数组中。为了减少扩容时数据的拷贝次数,ArrayList在扩容时通常会选择一个比当前容量大的多的新容量(通常是当前容量的1.5倍)。
ArrayList的默认初始容量为10,但你可以在创建ArrayList实例时指定一个初始容量。如果你知道将要存储的元素数量,提前指定一个合适的初始容量可以减少扩容时数据的拷贝次数,从而提高性能。

线程安全性

ArrayList是非线程安全的。这意味着如果多个线程同时修改ArrayList(例如,一个线程在遍历列表时,另一个线程在添加或删除元素),可能会导致数据不一致或其他并发问题。因此,在多线程环境中使用ArrayList时,需要进行额外的同步操作来确保线程安全。

元素存储和访问

由于ArrayList底层是一个数组,因此元素的存储和访问都基于数组的索引。添加元素时,ArrayList会将新元素存储在数组的末尾(或指定的索引位置),并更新列表的大小。访问元素时,ArrayList会根据提供的索引直接访问数组中的相应位置。由于数组在内存中是连续存储的,因此访问数组元素的时间复杂度是O(1)。
然而,由于ArrayList在添加元素时可能需要扩容并复制数组,因此在列表的中间位置添加或删除元素的时间复杂度可能较高(最坏情况下为O(n))。相比之下,在列表的开头或结尾添加或删除元素的时间复杂度通常是O(1),因为这两个位置的操作不需要移动其他元素。

总的来说,ArrayList是一个功能强大且灵活的数据结构,适用于需要在内存中存储和访问大量元素的情况。但是,在多线程环境中使用时需要注意线程安全问题

LinkedList

Java中的LinkedList底层原理主要基于双向链表数据结构。以下是关于LinkedList底层原理的总结:
数据结构

LinkedList使用双向链表作为其内部数据结构。双向链表中的每个节点(Node)都包含三个部分:
元素值(item):存储链表中的实际数据。
前节点引用(prev):指向链表中当前节点之前的节点。对于链表的第一个节点,此引用通常为null。
后节点引用(next):指向链表中当前节点之后的节点。对于链表的最后一个节点,此引用通常为null。

插入操作

在 LinkedList 中,增加操作同样依赖于其双向链表的特性。当你尝试向列表中添加一个新元素时,LinkedList 实际上会:

  1. 确定插入位置:根据提供的索引或方法(如 addFirst、addLast),LinkedList 会确定新元素应该插入的位置。
  1. 创建新节点:LinkedList 会创建一个新的节点(通常是一个内部类),该节点包含要添加的元素以及指向其前一个和后一个元素的引用(最初这些引用可能为空或指向其他元素)。
  1. 更新链接:根据插入位置,LinkedList 会更新新节点与其前一个和后一个元素的链接。具体来说,它会将新节点的 prev 引用指向前一个元素(如果存在的话),将新节点的 next 引用指向后一个元素(如果存在的话),并相应地更新前一个和后一个元素的引用。
  1. 维护大小:LinkedList 还会更新其内部的大小计数器,以反映列表中元素数量的增加。

注意事项

1.由于 LinkedList 是双向链表,因此在列表的任何位置进行删除或增加操作的时间复杂度都是 O(n),其中 n 是列表的大小。但是,由于不需要移动元素(如 ArrayList 在列表中间进行删除或增加时所做的那样),这些操作通常更快。
2.LinkedList 还提供了在列表开头和结尾进行高效删除和增加操作的方法(如 addFirst、addLast、removeFirst、removeLast),这些操作的时间复杂度是 O(1)。
3.由于 LinkedList 需要额外的空间来存储每个元素的引用,因此它在内存使用方面可能比基于数组的列表更高。

删除操作
在LinkedList中删除元素时,需要找到要删除的节点,并更新其前后节点的引用以断开连接。

  1. 删除头部节点:将头节点引用更新为其next节点,并设置新头节点的prev引用为null(如果新头节点不是null的话)。
    删除尾部节点:遍历链表找到倒数第二个节点,将其next引用设置为null。
  1. 删除指定索引的节点:遍历链表找到指定索引的节点,然后更新其前后节点的引用以断开连接。

访问操作

访问LinkedList中的元素通常需要通过遍历链表来实现,因为链表中的元素在内存中不是连续存储的。但是,由于LinkedList同时提供了向前和向后遍历的能力(通过ListIterator),因此访问操作在某些情况下可能比其他链表结构更高效。

线程安全性

与ArrayList和Vector不同,LinkedList本身不是线程安全的。如果多个线程同时修改LinkedList,则需要在外部进行同步操作以确保线程安全。但是,由于LinkedList的双向链表结构,它在并发修改时通常比基于数组的列表(如ArrayList)具有更好的性能。

性能特点

插入和删除操作:在链表的开头或结尾进行插入和删除操作的时间复杂度通常为O(1),因为只需要修改几个引用即可。在链表的中间进行插入和删除操作的时间复杂度为O(n),其中n是链表的长度,因为需要遍历链表以找到正确的位置。
访问操作:访问链表中的特定元素(如通过索引)需要遍历链表,因此其时间复杂度为O(n)。
空间效率:由于每个节点都需要额外的空间来存储引用(prev和next),因此LinkedList的空间效率略低于基于数组的列表(如ArrayList)。但是,这种差异在大多数情况下都是可以接受的,特别是当插入和删除操作的性能更重要时。

Vector

Java中的Vector类的底层原理主要涉及其数据结构、扩容机制、线程安全性以及元素存储和访问方式。以下是对Vector底层原理的总结:
数据结构

Vector的底层数据结构同样是一个动态数组。它内部维护了一个Object类型的数组,用于存储列表中的元素。与ArrayList类似,Vector也可以根据需要动态地增长或缩小其容量。

扩容机制>
当向Vector中添加元素时,如果当前数组的容量不足以容纳新元素,Vector会自动进行扩容。扩容操作涉及创建一个新的、容量更大的数组,并将原数组中的元素复制到新数组中。扩容的倍数通常是原容量的两倍,但具体实现可能因Java版本或JVM实现而异。

线程安全性

Vector是一个线程安全的类。它的所有方法(包括添加、删除、获取元素等操作)都是同步的,这意味着在多线程环境下,多个线程可以同时访问和修改Vector对象,而不会产生数据竞争和不一致的问题。然而,这种线程安全性是以牺牲性能为代价的,因为同步操作会引入额外的开销。

元素存储和访问

与ArrayList一样,Vector使用数组的索引来存储和访问元素。添加元素时,Vector会将新元素存储在数组的末尾(或指定的索引位置),并更新列表的大小。访问元素时,Vector会根据提供的索引直接访问数组中的相应位置。

性能考虑

虽然Vector提供了线程安全性,但在单线程环境下,由于同步操作的开销,它的性能通常不如ArrayList。因此,在不需要线程安全性的情况下,使用ArrayList通常是一个更好的选择。如果需要线程安全性,可以考虑使用Collections.synchronizedList()方法将ArrayList包装为线程安全的列表,或者使用CopyOnWriteArrayList等并发集合类。

总的来说,Vector是一个基于动态数组实现的线程安全的列表类。然而,由于同步操作的开销和性能考虑,它在现代Java编程中逐渐被其他并发集合类所取代。

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

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

相关文章

Linux课程机房虚拟机

Linux课程机房虚拟机 机房虚拟机(默认不能联网的): 百度网盘:https://pan.baidu.com/s/1WqSvqB3Y7b_D4690CDBlJA?pwdaugc 123网盘:https://www.123pan.com/s/tQ0UVv-LiolA.html提取码:F4xm ‍ 联网使用说明&…

小trick

https://codeforces.com/gym/105104/problem/C const int N 1e6 10;int T, n, x; ull v[N];int main() {mt19937_64 rng(random_device{}()); // 注意这种生成随机数的方法!!!F(i, 0, N - 10)v[i] rng();for (R(T); T --; ) {R(n);map &…

设计模式——观察者模式(Observer)

观察者模式(Observer Pattern)是软件设计模式的一种,也被称为模型-视图模式、源-收听者模式或从属者模式。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,它的所有…

笔记2:cifar10数据集获取及pytorch批量处理

(1)cifar10数据集预处理 CIFAR-10是一个广泛使用的图像数据集,它由10个类别的共60000张32x32彩色图像组成,每个类别有6000张图像。 CIFAR-10官网 以下为CIFAR-10数据集data_batch_*表示训练集数据,test_batch表示测试…

分成互质组

题目描述: 给定 n 个正整数&#xff0c;将它们分组&#xff0c;使得每组中任意两个数互质。 至少要分成多少个组&#xff1f; 输入格式 第一行是一个正整数 n。 第二行是 n 个不大于10000的正整数。 输出格式 一个正整数&#xff0c;即最少需要的组数。 #include<iostream…

DDR5和LPDDR4/5 命令解析

关键名称介绍 DDR5 SDRAM和LPDDR4/5都采用了高级的命令集来支持更高效的内存管理和操作,其中“Multi-purpose command (MPC)”、“Mode Register Read (MRR)”、“Mode Register Write (MRW)”,以及“Write Pattern Command”是几种关键的命令类型,它们在内存初始化、配置和…

Windows 虚机扩容C盘

Windows 虚机扩容C盘 操作思路1、新增磁盘容量2、划分磁盘空间3、扩容对应盘 操作步骤 操作思路 1、新增磁盘容量 2、划分磁盘空间 3、扩容对应盘 操作步骤 1、虚机新增磁盘空间 先确认宿主机是否有足够空间&#xff0c;有足够空间后&#xff0c;编辑虚机&#xff0c;增加…

【Java】山外有山,类外还有类

【Java】山外有山&#xff0c;类外还有类 内部类是Java语言中的一种特性&#xff0c;它允许在另一个类中定义一个类。 内部类可以是静态的&#xff08;不依赖于外部类的实例&#xff09;&#xff0c;也可以是非静态的&#xff08;依赖于外部类的实例&#xff09;。 在本篇博…

不止是搭建 | 极空间虚拟机安装一个可做生产力的Ubuntu桌面系统以及后续优化

不止是搭建 | 极空间虚拟机安装一个可做生产力的Ubuntu桌面系统以及后续优化 哈喽小伙伴们好&#xff0c;偶是Stark-C~ 我在上篇极空间文章中不是给小伙伴们分享了使用虚拟机安装软路由固件『iStoreOS』的教程嘛&#xff1a; 打造Docker完全体&#xff0c; 开箱即用的各类插…

vue3封装获取当前年、月、季度、周

1.新建在utils文件夹中handleTime.js文件用于封装方法 // 计算当前周的开始和结束时间 export function calcNowWeek() {let startWeek moment().weekday(0).format(YYYY-MM-DD);startWeek moment(startWeek).subtract(2, days).format(YYYY-MM-DD)let endWeek moment().we…

Kafka 环境搭建之伪分布式集群模式详细教程

Kafka 简介及相关组件介绍 Kafka 环境搭建和使用之单机模式详细教程 伪集群模式 Kafka伪集群是一种在单个机器上模拟多节点Kafka集群的配置方式,主要用于开发和测试环境。在伪集群模式下,你可以配置多个Kafka broker实例,它们都连接到同一个Zookeeper实例或者集群,从而模…

通过 Java 操作 redis -- hash 哈希表基本命令

目录 使用命令 hset&#xff0c;hget 使用命令 hexists 使用命令 hdel 使用命令 hkeys&#xff0c;hvals 使用命令 hmget&#xff0c;hmset 关于 redis hash 哈希表类型的相关命令推荐看Redis - hash 哈希表 要想通过 Java 操作 redis&#xff0c;首先要连接上 redis 服务…

员工满意度调查真实度难题如何攻克?

在企业管理实践中&#xff0c;员工满意度调查无疑扮演着举足轻重的角色。它不仅能够帮助企业洞察员工的真实心声&#xff0c;还是企业制定精准管理策略的重要依据。然而&#xff0c;很多时候&#xff0c;员工满意度调查的真实度却令人堪忧&#xff0c;让企业难以获得真实、有效…

手撕多线程

用一个双线程轮流打印1-100 // 定义一个类&#xff0c;用于交替打印奇偶数 public class AlternatePrinting {// 当前待打印的数字&#xff0c;初始为1private int currentNumber 1;// 用作线程间同步的锁对象private final Object lock new Object();// 程序入口public sta…

企业做网站,如何设计才有创意?

企业做网站&#xff0c;如何设计才有创意&#xff1f;我们都希望能打造一个有创意的网站建设&#xff0c;能在众多网站中脱颖而出&#xff0c;能够营销推广公司的产品&#xff0c;为公司带来更多的经济效益收益。广州网站建设的时候&#xff0c;记住直观的设计可以让用户体验更…

批处理脚本示例,用于删除特定目录下所有以 .pdb、.ilk、.lib、.map、.exp 结尾的文件:

以下是一个批处理脚本示例&#xff0c;用于删除特定目录下所有以 .pdb、.ilk、.lib、.map、.exp 结尾的文件&#xff1a; echo off set target_dirC:\path\to\directorydel /S /Q "%target_dir%\*.pdb" del /S /Q "%target_dir%\*.ilk" del /S /Q "%…

福州网站建设如何设计极简风格合理?

福州网站建设如何设计极简风格合理&#xff1f;企业网站逐渐流行&#xff0c;每个人的审美也发生着巨大的改变&#xff0c;开始追求一种极简的风格。简单的 风格才能够凸显原有的主题&#xff0c;不会太过主次不分。 越来越多的网站建设中选择极简的风格&#xff0c;简单的页面…

在Leaflet中点对象使用SVG和Canvas两种模式的对比

目录 前言 一、关于SVG和Canvas 1、SVG知识 2、Canvas知识 3、优缺点 二、SVG和Canvas在Leaflet的使用 1、相关类图 2、Leaflet的默认展示方式 三、SVG和Canvas实例及性能对比 1、SVG模式及性能对比 2、Canvas优化 总结 前言 众所周知&#xff0c;在Leaflet当中&#…

伪装坑人程序

如果直接把坑人程序复制粘贴&#xff0c;肯定会被发现&#xff0c;所以要这样&#xff01; 首先把坑人程序放到C盘的某个重要目录里这样没人注意 然后在显眼的地方创建快捷方式 然后找一个可以伪装的软件&#xff0c;就找到这个软件的快捷方式 右键单击&#xff0c;选择属性…

Datasophon基于dinky1.0.1升级到dinky1.0.2

1.首先下载dinky1.0.2版本 dinky1.0.2下载地址 2.关闭dinky1.0.1 3.升级dinky1.0.2 3.1 解压dinky1.0.2.ta.gz tar -xzvf dinky-release-1.16-1.0.2.tar.gz -C /opt/datasophon/rm -rf dinky-release-1.16-1.0.2.tar.gz复制dinky1.0.1的配置文件到dinky1.0.2目录 cp /op…