Java的集合框架总结

Map接口和Collection接口是所有集合框架的父接口:

  1. Collection接口的子接口包括:Set接口和List接口

  1. Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等

  1. Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等

  1. List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等

List接口及其实现

ArrayList

  • 基于动态数组实现

  • 允许快速随机访问元素

  • 插入和删除操作可能需要移动其他元素,因此在中间位置插入和删除的时间复杂度为O(n)

  • 非同步,不是线程安全的,可以使用使用Collections.synchronizedList(new ArrayList<>()) 创建一个同步的 ArrayList

LinkedList
  • 基于双向链表实现

  • 允许快速插入删除元素

  • 不能快速随机访问,访问元素的时间复杂度为O(n)

  • 非同步,不是线程安全的。可以使用 Collections.synchronizedList(new LinkedList<>()) 创建一个同步的 LinkedList

  • 可以用做队列或双向队列

    依赖于两个节点(一个头节点一个尾节点)

    常用方法

    添加

    add(E e):在链表后添加一个元素; 通用方法 addFirst(E e):在链表头部插入一个元素; 特有方法 addLast(E e):在链表尾部添加一个元素; 特有方法

    删除

    removeFirst(E e):删除头,获取元素并删除; 特有方法 removeLast(E e):删除尾; 特有方法

    查看

    getFirst():获取第一个元素; 特有方法 getLast():获取最后一个元素; 特有方法

Stack
  • 基于Vector实现,代表了后进先出()

  • 是同步的,是线程安全的

  • push入栈、peek查看栈顶元素、pop出栈、empty是否为空、size()获取数目

Vector
  • 基于动态数组实现,类似于ArrayList

  • 同步的,是线程安全的

  • 是需要线程安全的动态数组是使用,但是通常使用ArrayListCollections.syschronizedList来代替

Set接口及其实现类

set其实一直在用map那一套

 public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {private transient HashMap<E,Object> map;private static final Object PRESENT = new Object();​public HashSet() {map = new HashMap<>();}​public boolean add(E e) {return map.put(e, PRESENT) == null;}​// Other methods delegate to the underlying map}​
HashSet
  • 元素存储HashSet 将元素添加到底层的 HashMap 中,键是元素的哈希码,值是一个占位符对象。HashSet的实现是基于HashMap的,他使用HashMap来存储元素,在HashSet中,元素被当作HashMap的键,而HashMap的值则是一个固定的占位符,通常是 PRESENT 对象(一个静态内部类对象)。这样做是为了节省空间,因为 HashSet 只关心元素的唯一性,不需要存储额外的值。

  • 去重HashSet 使用了 HashMap 键的唯一性来确保 HashSet 中不会有重复的元素。

  • 不保证集合的迭代顺序,顺序可能会随时间变化。

  • 方法委派HashSet 的许多方法(如 addremovecontains 等)都是通过调用底层 HashMap 的对应方法来实现的。

  • 性能:由于 HashSet 是基于 HashMap 实现的,所以其性能与 HashMap 类似,添加、删除和查找操作的平均时间复杂度为 O(1)。

  • 允许存储null值。

LinkedHashSet

LinkedHashSetHashSet 的一个子类,它继承了 HashSet 的特性,并且保持了元素的插入顺序。下面是关于 LinkedHashSet 的一些关键点:

  • 继承自HashSet并且使用链表维护元素的插入顺序

  • 保证迭代顺序与插入顺序一致

  • 允许存储null值。

  • 插入、删除、和查找操作的时间复杂度为O(1)。

实现细节

  • 当你向 LinkedHashSet 添加元素时,它会使用 LinkedHashMap 来存储元素。

  • 每个元素被当作 LinkedHashMap 的键,值则是一个固定的占位符对象。

  • LinkedHashSet 通过委派 LinkedHashMap 来实现其 addremovecontains 等方法。

TreeSet

TreeSet 是 Java 中实现 SortedSet 接口的一个集合类,它基于 TreeMap 实现,并且元素是按照自然顺序(或通过提供的比较器)排序的。以下是 TreeSet 的一些关键点:

  • 基于红黑树(自平衡二叉搜索树)实现

  • 元素是有序的,元素按照自然顺序(或通过Comparator指定的顺序)排

  • 不允许存储null值(会抛出NullPointerException

  • 插入、删除、和查找操作的时间复杂度为O(log n)。

Map接口及其实现类
HashMap

  • 基于哈希表实现,调用put方法值,首先将k,v封装到Node对象中,然后底层会调用k的hashCode()方法得到hash值。根据这个值来决定到底该插入数组下标的哪个位置,如果有两个值的哈希值一样,就会调用equals方法进行比较,如果哈希值一样但是不相等,就会形成链表插入 ,如果相等那么相等的这个节点的value将会被覆盖。如果没有元素占用位置,就直接放入即可。(通过数组加链表形式)

  • 在Java8对hashmap进行了优化,如果相同哈希值,链表的长度超过8,就从链表转换成红黑树。第一次添加元素的时候,默认初期长度为16,当往map中继续添加元素的时候,通过hash值跟数组长度取“与”来决定放在数组的哪个位置,如果出现放在同一个位置的时候,优先以链表的形式存放,在同一个位置的个数又达到了8个(代码是>=7,从0开始,及第8个开始判断是否转化成红黑树),如果数组的长度还小于64的时候,则会扩容数组。如果数组的长度大于等于64的话,才会将该节点的链表转换成树。在扩容完成之后,如果某个节点的是树,同时现在该节点的个数又小于等于6个了,则会将该树转为链表(只有当数据量大于64才会有红黑树+链表)

  • HashMap内部结构是数组(Node[] table)和链表结合组成的复合结构,数组被分成一个个桶(bucket)或槽,通过哈希值决定键值对在这个数组的寻址;哈希值相同的键值对,则以链表形式存储。当链表大小超过阈值(TREEIFY_THRESHOLD = 8)时,链表就会被改造成树形结构。(查询效率变高)

  • Java8不再像Java7中那样需要满足两个条件,Java8中扩容只需要满足一个条件:当前存放新值(注意不是替换已有元素位置时)的时候已有元素的个数大于等于阈值(已有元素等于阈值,下一个存放后必然触发扩容机制)且扩容发生在存放后,即是数据存放后(先存放后扩容),判断当前存入对象的个数,如果大于阈值则进行扩容。

  • 允许存储null键和null值。

  • 插入、删除、和查找操作的时间复杂度为O(1)。

  • 非同步,不是线程安全的。

LinkedHashMap

  • 通过hashmap跟双向链表实现,可以确保按照插入顺序迭代链表

  • 遍历性能: 与普通的HashMap相比,在迭代LinkedHashMap时,性能更加稳定。因为它不需要遍历整个桶,而是按照链表顺序遍历元素。

  • 实现方式: 在内部实现上,LinkedHashMap在每个条目中保留了前一个和后一个条目的引用,以实现双向链表。这使得在插入、删除和遍历元素时的性能表现良好。

TreeMap

  • 基于红黑树实现

  • 键按照自然顺序(或通过Comparator指定的顺序)排序。

  • 不允许存储Null键

  • 插入、删除、和查找操作的时间复杂度为O(log n)。

Hashtable
  • 也是使用哈希表还有链表实现

  • 同步的,是线程安全的。

  • 不允许存储null键和null值。

  • 插入、删除、和查找操作的时间复杂度为O(1)。

Properties
  • 继承自Hashtable,表示一个持久化的属性集。

  • 每个键及其对应值都是一个字符串。

  • 常用于读取和写入配置文件。

ConcurrentHashMap
  • 不允许存储null键和null值。

  • 插入、删除、和查找操作的时间复杂度为O(1)。

  • 在多线程环境下,使用HashMap进行put操作时存在丢失数据的情况,为了避免这种bug的隐患,强烈建议使用ConcurrentHashMap代替HashMap。

  • HashTable是一个线程安全的类,它使用synchronized来锁住整张Hash表来实现线程安全,即每次锁住整张表让线程独占,相当于所有线程进行读写时都去竞争一把锁,导致效率非常低下。ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,允许多个修改操作并发进行,其关键在于使用了锁分段技术。它使用了多个锁来控制对hash表的不同部分进行的修改。

分段锁(Segment Locking)机制

早期版本的ConcurrentHashMap(Java 7及之前)使用分段锁机制,具体如下:

  • ConcurrentHashMap内部将整个哈希表分为多个段(Segment),每个段都是一个独立的哈希表,并拥有自己的锁。

  • 这种机制允许多个线程同时访问不同段的元素,从而提高并发度。

  • ConcurrentHashMap 为了提高本身的并发能力,在内部采用了一个叫做 Segment 的结构,一个 Segment 其实就是一个类 Hash Table 的结构,Segment 内部维护了一个链表数组,我们用下面这一幅图来看下 ConcurrentHashMap 的内部结构,从下面的结构我们可以了解到,ConcurrentHashMap 定位一个元素的过程需要进行两次Hash操作,第一次 Hash 定位到 Segment,第二次 Hash 定位到元素所在的链表的头部,因此,这一种结构的带来的副作用是 Hash 的过程要比普通的 HashMap 要长,但是带来的好处是写操作的时候可以只对元素所在的 Segment 进行操作即可,不会影响到其他的 Segment,这样,在最理想的情况下,ConcurrentHashMap 可以最高同时支持 Segment 数量大小的写操作(刚好这些写操作都非常平均地分布在所有的 Segment上),所以,通过这一种结构,ConcurrentHashMap 的并发能力可以大大的提高。

CAS操作和分段锁

在Java 8中,ConcurrentHashMap使用了一种新的机制,结合了CAS(Compare-And-Swap)操作和细粒度的分段锁。

  • 使用CAS操作来保证对单个节点的原子性操作,减少锁的使用。

  • 在插入、删除和更新操作中,如果CAS操作失败(即另一个线程同时修改了相同的位置),则退而使用锁进行操作。

  • 在Java 8中,ConcurrentHashMap取消了分段锁的概念,直接在哈希桶(bucket)级别进行锁定,使用CAS操作和synchronized块来保证并发安全。这使得数据结构更加简单,且操作更加直观。

  • 为了优化哈希冲突情况下的查找性能,Java 8引入了红黑树。当链表的长度超过一定阈值(默认是8)时,链表会转换为红黑树。这样,在高冲突情况下,查找操作的时间复杂度从O(n)降到了O(log n),极大地提高了性能。

  • CAS 操作通过比较当前值与预期值,如果两者相等则更新为新值,否则重试该操作。

数据结构

ConcurrentHashMap在Java 8中的内部数据结构有以下几个关键组成部分:

  • 数组(Node<K,V>[] table):哈希表的核心数组,存储链表或红黑树的头节点。

  • 链表和红黑树:数组中的每个桶(bucket)最初是一个链表。当链表长度超过阈值(8)时,链表会转换为红黑树,以提高查询效率。

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

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

相关文章

大数据实训项目(小麦种子)-03、大数据环境Hadoop、Mapreduce、Hive、Hbase、HDFS搭建服务及调试

文章目录 前言一、Linux系统Centos7安装配置JDK8二、Linxu系统Centos7中搭建Hadoop3.1.0服务下载地址服务1&#xff1a;详细步骤&#xff08;初始化与启动dfs服务&#xff09;详细步骤配置环境变量 服务2&#xff1a;Hadoop(YARN)环境搭建 三、Linux系统搭建Hive3.1.2服务前提条…

记录AE快捷键(持续补充中。。。)

记录AE快捷键 快捷键常用快捷键图层快捷键工具栏图层与属性常用指令视图菜单时间轴常规快捷键项目首选项功能摄像机操作 常用操作导入AI/PS工程文件加选一个关键参数快速回到上下一帧隐藏/显示图层关键帧拉长缩短关键帧按着鼠标左键不松手&#xff0c;在秒表那一列往下移动会都…

QT面试宝典:看你会了几道题?

目录 进程和线程的区别及其同步方式 堆栈的区别和使用场景 常用的排序算法及其时间与空间复杂度 数组和链表的区别和适用场景 回调函数的典型使用场景 static 和 const 关键字的区别和使用 元对象系统的作用和实现原理 信号与槽机制的优势和不足 QT事件机制的不同级别…

深度学习(PyTorch)批注理解,建议边学可以边看这个笔记

前言 动手学习深度学习&#xff0c;内容丰富&#xff0c;但是对于初学者有很多晦涩难懂的地方&#xff0c;我将日常更新这篇文章以截图的形式&#xff0c;每天高强度学习四五个小时&#xff0c;精力缺乏&#xff0c;我认为&#xff0c;如果想学习这个深度学习&#xff0c;你需…

ubuntu vnc

如何在Ubuntu 18.04安装VNC | myfreax sudo apt install xfce4 xfce4-goodies xorg dbus-x11 x11-xserver-utils sudo apt install tigervnc-standalone-server tigervnc-common vncserver sudo apt install xfce4 xfce4-goodies xorg dbus-x11 x11-xserver-utils sudo apt ins…

MFC序列号输入框

在MFC&#xff08;Microsoft Foundation Classes&#xff09;中创建一个对话框的过程&#xff0c;该对话框用于输入序列号&#xff08;SN&#xff09;&#xff0c;并具有一些特定的行为&#xff0c;比如自动聚焦到输入框、验证输入规则以及根据输入情况关闭对话框。以下是步骤说…

Unity3D MMORPG多玩家状态同步详解

一、引言 在Unity3D开发的MMORPG&#xff08;大型多人在线角色扮演游戏&#xff09;中&#xff0c;多玩家状态同步是一个至关重要的技术环节。它确保了在大量玩家同时在线时&#xff0c;服务器和客户端之间能够保持状态的一致性&#xff0c;从而提供流畅且准确的游戏体验。本文…

5.数据仓库与数据挖掘期末复习

ETL的含义Extract 、 Transformation、Load。ODS的全称Operational Data Store。 DW全称 Data WarehourseDM全称是Data Mart数据仓库数据抽取时所用到技术是增量、全量、定时、调度STAGE层作用是提供业务系统数据文件的临时存储ODS层作用ods提供业务系统细节数据长期沉淀MID层…

实用软件下载:BetterZip 5最新安装包及详细安装教程

BetterZip是一款功能强大的Mac解/压缩软件&#xff0c;可以满足用户对文件压缩、解压、加密和保护等方面的需求。以下是关于BetterZip软件的主要功能、特点和使用方法的详细介绍&#xff0c;以及对其用户友好度、稳定性和安全性的评价。 安 装 包 获 取 地 址: BetterZip 5-安…

057、PyCharm 运行代码报错:Error Please select a valid Python interpreter

当我们在PyCharm运行代码时&#xff0c;提示如下图错误&#xff1a; 那么问题通常是由于PyCharm未正确配置Python解释器引起的。 我们只需按以下步骤重新配置Python解释器即可&#xff1a; 打开PyCharm设置&#xff1a; 在菜单栏中的点击 “File” -> “Settings”&#xf…

选择性语言建模:下一代语言模型训练方法

在人工智能领域&#xff0c;语言模型的预训练方法一直是研究的热点。传统的语言模型预训练方法普遍采用一种均匀的策略&#xff0c;即对所有训练数据中的下一个词进行预测&#xff0c;这种方法被称为因果语言建模&#xff08;Causal Language Modeling, CLM&#xff09;。虽然C…

Nginx配置详细解释:(6)实现反向代理服务器,动静分离,负载均衡

目录 单台反向代理 proxy_pass后面加不加/的问题&#xff1a; 反向代理动静分离 反向代理负载均衡 作为代理服务器是当客户端访问代理服务器时&#xff0c;代理服务器代理客户端去访问真实web服务器。proxy_pass; 用来设置将客户端请求转发给的后端服务器的主机。 需要模块…

Web前端弱势因素:深入探讨与挑战解析

Web前端弱势因素&#xff1a;深入探讨与挑战解析 在快速发展的Web前端领域&#xff0c;尽管技术日新月异&#xff0c;但仍存在一些固有的弱势因素。这些因素不仅影响了开发效率和用户体验&#xff0c;也带来了诸多挑战。本文将深入探讨Web前端的弱势因素&#xff0c;并从四个方…

【C++11 之rbegin()、rend() 反向迭代器原理介绍及 重点-限制情况】与正向迭代器对比(互换放在下一p)

C11 引入了许多新特性&#xff0c;其中包括对 STL&#xff08;Standard Template Library&#xff09;的改进。在 STL 容器中&#xff0c;rbegin() 和 rend() 是两个新的成员函数&#xff0c;它们分别返回指向容器最后一个元素的反向迭代器&#xff08;reverse iterator&#x…

你不知道的HTML5应用程序缓存:深度揭秘与进阶实践

在HTML5的众多革新之中&#xff0c;应用程序缓存&#xff08;AppCache&#xff09;常常被视为一项被忽视的宝藏。尽管近年来Service Workers逐渐取代了它的位置&#xff0c;AppCache在特定场景下仍展现了其独特的魅力与价值。本文旨在深入挖掘HTML5应用程序缓存的隐藏功能、常见…

Android入门第69天-AndroidStudio中的Gradle使用国内镜像最强教程

背景 AndroidStudio默认连接的是dl.google的gadle仓库。 每次重新build时: 下载速度慢;等待了半天总时build faild;build到一半connection timeout;即使使用了魔法也难以一次build好;这严重影响了我们的学习、开发效率。 当前网络上的使用国内镜像的教程不全 网上的教程…

C++ shared_ptr

shared_ptr共享它指向的对象&#xff0c;多个shared_ptr可以指向&#xff08;关联&#xff09;相同的对象&#xff0c;在内部采用计数机制来实现。 当新的shared_ptr与对象关联时&#xff0c;引用计数增加1。 当shared_ptr超出作用域时&#xff0c;引用计数减1。当引用计数变为…

YOLOv8改进 | 注意力机制 | 添加适用于遥感图像的LSKblock注意力——【二次创新+完整代码】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 遥感目标检测的研究主要集中在改进方向边界框的表示上,而忽略了遥感场景中独特的先验知识。 这类先验知识对于准确检测微小目标至关重要,因为这些目标往往需要更大的上下文信息才能被正确识别。提出的 LSKNet …

根据身份证获取生日、性别、年龄

当type1时获取出生日期,type2时获取性别,type3时获取年龄 /** 当type1时获取出生日期,type2时获取性别,type3时获取年龄* */ function IdCard(IdCard, type) {if (type 1) {//获取出生日期let birthday IdCard.substring(6, 10) "-" IdCard.substring(10, 12) …

正式环境下的历史数据迁移方案,你知道几个?

一、历史数据库 MySQL 数据库可以很好地支撑海量的 OLTP(Online Transaction Processing)的系统,但是对于海量的互联网业务来说,数据量是非常巨大的。 假设一天 10 亿笔交易,每笔交易至少需要有一条记录,用于记录该笔交易,这就是通常所谓的流水数据。再假设一笔流水占…