集合框架知识
xsobi 2024-11-23 10:51 10 浏览
Java的集合类主要由两个接口派生而出:Collection和Map
Set、List和Map可以看做集合的三大类:
List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集
合里元素不允许重复的原因)。
Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。
ArrayList
有序可重复,允许为空非安全的初始容量为10的动态数组
ArrayList类中两个私有属性,elementData存储ArrayList内的元素,size表示它包含的元素的数量。
有序:元素是按照该 collection 的迭代器返回它们的顺序排列的。
动态扩容:int newCapacity = (oldCapacity * 3)/2 + 1;
插入元素:按照指定位置,把从指定位置开始的所有元素利用System.arraycopy方法做一个整
体的复制,向后移动一个位置(当然先要用ensureCapacity方法进行判断,加了一个元素之后数组会
不会不够大),然后指定位置的元素设置为需要插入的元素,完成了一次插入的操作,该方法的根本目的就是将index位置空出来以供新数据插入,这里需要进行数组数据的右移,如果要复制的元素很多,那么就会比较耗费性能。
删除元素:1、把指定元素后面位置的所有元素,利用System.arraycopy方法整体向前移动一个位置
2、最后一个位置的元素指定为null,这样让gc可以去回收它,如果要复制的元素很多,那么就会比较耗费性能。
访问元素:ArrayList底层以数组实现,是一种随机访问模式,再加上它实现了RandomAccess接口,因此查
找也就是get的时候非常快。基于数组实现,可以通过下标索引直接查找到指定位置的元素,因此查找效率高
ArrayList是线程非安全的,一个方法是用Collections.synchronizedList方法把你的ArrayList变成一个线程安全的List,另一个方法就是Vector,它是ArrayList的线程安全版本
LinkedList
有序可重复,允许为空非安全的初始容量为10的双向链表
LinkedList中定义了两个私有属性:size 和Entry (Entry中包含成员变量:previous, next,element)
LinkedList底层的数据结构是基于双向循环链表的,且头结点中不存放数据,数据结构——我们可以称之为节点,节点实例保存业务数据、前一个节点的位置信息和后一个节点位置信息
插入元素:改变前后Entry的引用地址
删除元素:预删除节点的前一节点的后指针指向预删除节点的后一个节点。预删除节点的后一节点的前指针指向预删除节点的前一个节点。清空预删除节点:交给gc完成资源回收,删除操作结束。与ArrayList比较而言,LinkedList的删除动作不需要“移动”很多数据,从而效率更高。
访问元素:get(int)方法首先判断位置信息是否合法(大于等于0,小于当前LinkedList实例的Size),然后遍历
到具体位置,获得节点的业务数据(element)并返回。当index小于数组大小的一半的时候(size >> 1表示size / 2,使用移位运算提升代码运行效率),从前向后查找;否则,从后向前查找。
ArrayList和LinkedList比较
(1)LinkedList做插入、删除的时候,慢在寻址,快在只需要改变前后Entry的引用地址
(2)ArrayList做插入、删除的时候,慢在数组元素的批量copy,快在寻址
HashMap
无序可重复,允许为空线程非安全的 链表的数组
构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
无序:特别说明这个无序指的是遍历HashMap的时候,得到的元素的顺顺序
可重复:Key重复会覆盖、Value允许重复)
Key和Value都允许为空
非线程安全的
HashMap的底层主要是基于数组和链表来实现的,它之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储的位置。(key 的hash值决定位置)HashMap中主要是通过key的hashCode来计算hash值的,只要
hashCode相同,计算出来的hash值就一样。
如果存储的对象对多了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。学过数据结构的同学都知道,解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的。
Entry就是数组中的元素,每个 Map.Entry 其实就是一个key-value对,它持有一个指向下一个元素的引用,这就构成了链表。(previous element next)
构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap: 空间利用和查找效率最好
加载因子它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。;如果负载因子太小,那么散列表的数据将过于稀疏,对空间造成严重浪费 ; 加载因子越大,填满的元素越多,好处是,空间利用率高了,但:冲突的机会加大了.链表长度会越来越长,查找效率降低。
存储元素(读取):先判断key是否为null,若为null,则直接
调用putForNullKey方法,将value放置在数组第一个位置上。若不为空则根据key的hashCode重新
计算hash值,然后根据hash值得到这个元素在table数组中的位置(即下标),如果table数组在该位
置处已经存放有其他元素了,则通过比较是否存在相同的key,若存在则覆盖原来key的value,否则
将该元素保存在链头(最先保存的元素放在链尾)。若table在该处没有元素,就直接将该元素放到此
数组中的该位置上。
通过比较是否存在相同的key,若存在则覆盖原来key的value:对比Key是否相同,是先比HashCode是否相同,HashCode相同再判断equals是否为true
访问元素:此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该
key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后
取出该索引处的 Entry,最后返回该 key 对应的 value 即可
2的n 次方:
HashMap的table而言,数据分布需要均匀(最好每项都只有一个元素,这样就可以直接找到),不能太紧也不能太松,太紧会导致查询速度慢,太松则浪费空间。HashMap的底层数组长度总是2的n次方数据在table数组中分布较均匀,查询速度也较快。
LinkedHashMap
HashMap+LinkedList,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序有序可重复
HashMap迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。我们期待一个有序的Map。LinkedHashMap就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序,该迭代顺序可以是插入顺序或者是访问顺序。
利用LinkedHashMap实现LRU算法缓存
LRU:LRU即Least Recently Used,最近最少使用,也就是说,当缓存满了,会优先淘汰那些最近最不常访问的数据。比
LinkedHashMap可以实现LRU算法的缓存基于两点:
1、LinkedList首先它是一个Map,Map是基于K-V的,和缓存一致
2、LinkedList提供了一个boolean值可以让用户指定是否实现LRU
accessOrder 1)false,所有的Entry按照插入的顺序排列(2)true,所有的Entry按照访问的顺序排列
concurrentHashMap
背景: 线程不安全的HashMap 使用Hashmap进行put操作会引起死循环 ;
效率低下的HashTable容器 , 当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法
时,可能会进入阻塞或轮询状态。
ConcurrentHashMap的锁分段技术(数据分段存储,分段枷锁)
首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
数据结构:
ConcurrentHashMap为了提高本身的并发能力,在内部采用了一个叫做Segment的结构,一个Segment其实就是一个类Hash Table的结构,Segment内部维护了一个链表数组。当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。
高并发:ConcurrentHashMap定位一个元素的过程需要进行两次Hash操作,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部。在最理想的情况下,ConcurrentHashMap可以最高同时支持Segment数量大小的写操作(刚好这些写操作都非常平均地分布在所有的Segment上),所以,通过这一种结构,ConcurrentHashMap的并发能力可以大大的提高。总的Map包含了16个Segment(默认数量),每个Segment内部包含16个HashEntry(默认数量),这样对于这个key所在的Segment加锁的同时,其他15个Segmeng还能正常使用,在性能上有了大大的提升。
详细解释一下Segment里面的成员变量的意义:
count:Segment中元素的数量
modCount:对table的大小造成影响的操作的数量(比如put或者remove操作)
threshold:阈值,Segment里面元素的数量超过这个值依旧就会对Segment进行扩容
table:链表数组,数组中的每一个元素代表了一个链表的头部
loadFactor:负载因子,用于确定threshold
volatile的保证:对volatile域的写入操作happens-before于每一个后续对同一个域的读写操作。所以,每次判断count变量的时候,即使恰好其他线程改变了segment也会体现出来。
get方法没有使用锁来同步,只是判断获取的entry的value是否为null,为null时才使用加锁的方式再次去获取。
put 操作:首先对Segment的put操作是加锁完成的。因为每个HashEntry中的next也是final的,没法对链表最后一个元素增加一个后续entry所以新增一个entry的实现方式只能通过头结点来插入了。
remove 操作:先定位Segment的过程,然后确定需要删除的元素的位置, 程序就将待删除元素前面的那一些元
素全部复制一遍,然后再一个一个重新接到链表上去,
- 上一篇:算法 | 位运算实现乘除
- 下一篇:C++数据结构:快速幂
相关推荐
- 在 Linux 系统中安装 Redis 的详细步骤
-
以下是在Linux系统中安装Redis的详细步骤,支持通过包管理器安装(简单快捷)和源码编译安装(获取最新版本)两种方式:方法1:使用包管理器安装(推荐新手)适用于Ubuntu/De...
- 在Linux系统上安装Redis集群的详细步骤
-
以下是在Linux系统上安装Redis集群的详细步骤,基于Redis6.x+版本,采用三主三从(6个节点)的典型配置模式:1.安装前准备环境要求系统:Ubuntu/CentOS等主流Linux发行...
- Linux入门使用教程
-
Linux入门一、初始化配置CentOS初始化安装在开始熟悉Linux操作命令之前,我们必须先搭建好Linux操作系统环境,我们这里选用的是Linux的发行版本CentOS7,在安装好CentOS操作...
- 06新手学习:Linux入门级命令教程
-
1、开启终端问题:什么是终端(Terminal)答:Linux操作系统中用于输入命令的位置打开后,效果如下图所示:2、Linux命令格式什么是Linux的命令?答:就是指在Linux终端(命令行)...
- 【笔记】windows10安装linux双系统教程(可能是现今最简单方法)
-
这周测试成功了大牛漂移菌教的树莓派系统镜像的压缩方法(【树莓派】小空间树莓派镜像系统备份方法img镜像文件压缩方法),虚拟机下备份镜像不太方便,无论是存储空间还是读卡操作都不方便。所以打算装个linu...
- 网络安全工程师:小白是如何让Kali Linux操作系统从U盘成功启动
-
一、背景介绍作为一名渗透测试工作人员(或者小白),在我们的日常工作或者学习中,我们不可能时时刻刻将自己的个人电脑(安装好KaliLinux的个人主机)带在身边,当我们没有带自己的个人电脑而需要进行渗...
- Linux配置ip地址的两种方法
-
Linux配置ip地址的两种方法,实验环境为centos7.6方法1:nmcli工具配置(centos7以下版本不支持该方法)第一步,通过nmcliconnection查看网卡名称[root@lo...
- Linux man 命令使用教程
-
简介man=manual(手册)命令用来查看Linux系统命令、函数、配置文件、系统调用等的官方文档。几乎所有标准程序和工具都有对应的man手册。基本语法man[options][s...
- Linux程序安装与管理指南
-
在Linux系统中,安装和管理程序主要通过包管理器和手动编译安装两种主要方式实现。以下是详细的操作指南,涵盖常见发行版(如Ubuntu/Debian、CentOS/RHEL、Fedora等)的用法。一...
- 零基础保姆级教程!手把手教你免费玩转Linux安装+学习环境搭建!
-
前期准备安装VMware虚拟机首先你要安装VMware虚拟机,如果你还不知道VMware是什么可以去看我的VMware相关教程,里面有详细解答检查V-CPU虚拟化是否开启当我们在虚拟机安装系统的...
- 网络安全工程师:小白如何使用Kali Linux生成木马后门并实现免沙
-
1.背景介绍msfvenom是msfpayload和msfencode的结合体,可利用msfvenom生成木马程序,并在目标机上执行,在本地监听上线,在黑客圈子,这款工具略有名气。本次教程是Msfve...
- Linux详解系列一:如何安装系统及客户端工具的使用
-
Linux是一种开放源码的操作系统,和Windows不同的是,由于其具有开源,稳定性强,安全,多用户操作等特点,它的使用场景非常广泛,比如企业中所使用的服务器中的操作系统,以及移动端的Andr...
- 4种方案供你选,微软发布《如何下载和安装Linux》教程
-
IT之家10月14日消息,微软近日发布了一个教程指南《如何下载和安装Linux》,介绍了使用WSL、本地安装、本地虚拟机和云端虚拟机4种方案。该指南重点介绍了用户在PC上运行Li...
- 嵌入式Linux开发教程:Linux Shell
-
本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...
- Linux基础手把手教学:使用22.04系统
-
Linux基础手把手教学:使用Ubuntu22.04系统。1.这节来讲一下下边的目录结构,因为只有清楚了解linux下边的目录结构,才能很方便地进行操作。linux下边的目录结构较为简单...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- characterencodingfilter (33)
- getmonth (34)
- label换行 (33)
- android studio 3 0 (34)
- html转js (35)
- 索引的作用 (33)
- checkedlistbox (34)
- xmlhttp (35)
- mysql更改密码 (34)
- 权限777 (33)
- htmlposition (33)
- 学校网站模板 (34)
- textarea换行 (34)
- 轮播 (34)
- asp net三层架构 (38)
- bash (34)