Java技术栈总结:容器集合篇

一、List

1、ArrayList

(1)底层数据结构

底层数据结构为数组。数组是一种用连续的内存空间存储相同数据类型数据的线性数据结构。

Q:为什么数组索引下标从0开始?

A:从0开始,对应寻址公式:a[i] = baseAddress + i * dataTypeSize;

如果从1开始,则变为:a[i] = baseAddress + (i-1)* dataTypeSize;需要增加一次减法操作,对于CPU来说就多了一次指令,性能不高。

其中,baseAddress: 数组的首地址,dataTypeSize:代表数组中元素类型的大小,int型的数据,dataTypeSize=4个字节

(2)实现原理

ArrayList初始容量为0,当第一次添加数据的时候才会初始化容量为10;

ArrayList在进行扩容的时候是原来容量的1.5倍,每次扩容都需要拷贝数。

【添加逻辑】

  • 添加过程确保数组已使用长度(size)加1之后足够存下下一个数据​ ;
  • 计算数组的容量,如果当前数组已使用长度+1后的大于当前的数组长度,则调用grow方法扩容(原来的1.5倍)
  • 确保新增的数据有地方存储之后,则将新元素添加到位于size的位置上。​

(3)数组和List转换

  • 数组转List ,使用JDKjava.util.Arrays工具类的 asList 方法;
  • lList转数组,使用 List 的 toArray 方法。无参 toArray 方法返回 Objec t数组,传入初始化长度的数组对象,返回该对象数组。

Q:① 用Arrays.asListList后,如果修改了数组内容,list受影响吗;② List用toArray转数组后,如果修改了List内容,数组受影响吗

A: 

  • Arrays.asList转换list之后,如果修改了数组的内容,list会受影响,因为它的底层使用的Arrays类中的一个内部类ArrayList来构造的集合,在这个集合的构造器中,把我们传入的这个集合进行了包装而已,最终指向的都是同一个内存地址;
  • list用了toArray转数组后,如果修改了list内容,数组不会影响,当调用了toArray以后,在底层是它是进行了数组的拷贝,跟原来的元素就没啥关系了,所以即使list修改了以后,数组也不受影响。

2、LinkedList

LinkedList 是双向链表的数据结构实现。

3、线程安全的List

<Vector、synchronizedList、CopyOnWriteArrayList>

(1)Vector

  • 使用synchronized修饰主要的方法;
  • 对整个list对象加锁。

(2)synchronizedList

通过Collections的静态方法创建。Collections.synchronizedList(List<T> list)

  • 使用synchronized修饰代码块;
  • 读写操作都会加锁。

(3)CopyOnWriteArrayList

读读操作及读写操作均不互斥,读操作不加锁,写操作(set、add、remove等)使用ReentrantLock加锁。

  • 列表内的数组“array”使用volatile修饰,保证不同线程间的可见性;
  • 写操作创建新的“数组”复制旧“数组”的数据,在新数组上进行修改,修改后调用“setArray”方法,将列表引用的数组指向到新数组;
  • 写操作加了“独占锁”,写操作本身不会出现线程安全问题。

【总结】:

  • 线程安全的List可以通过Vector、Collections.synchronizedList()方法、CopyOnWriteArrayList三种方式实现;
  • 读多写少的情况下,推荐使用CopyOnWriteArrayList;
  • 读少写多的情况下,推荐使用Collections.synchronizedList()。

二、Map

1、HashMap

散列表(Hash Table)又名哈希表/Hash表,是根据键(Key)直接访问在内存存储位置的值(Value)的数据结构,由数组演化而来的,利用了数组支持按照下标进行随机访问数据的特性。

将键(key)映射为数组下标的函数叫做散列函数。可以表示为:hashValue = hash(key)

散列函数的基本要求:

  • 散列函数计算得到的散列值必须是大于等于0的正整数,因为hashValue需要作为数组的下标;
  • 如果key1==key2,那么经过hash后得到的哈希值也必相同即:hash(key1) == hash(key2);
  • 如果key1 != key2,那么经过hash后得到的哈希值也必不相同即:hash(key1) != hash(key2);

散列冲突,不同的key经过hash运算得到相同的值。

散列冲突的解决,拉链法

在散列表中,数组的每个下标位置我们可以称之为 桶(bucket或者 槽(slot,每个桶()会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中。

(1)实现原理

数据结构:数组+链表+红黑树

位置:根据key的hash值确定在数组中的位置,方法“hash(key) & (n-1)”,其中 n 为数组长度。

链表与红黑树转换:链表长度到 8,且数组长度达到64,转为红黑树;减少到 6,转为链表。

1. 当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标

2. 存储时,如果出现hash值相同的key,此时有两种情况。

 a. 如果key相同,则覆盖原始值;

 b. 如果key不同(出现冲突),则将当前的key-value放入链表或红黑树中

3. 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。


(2)put方法执行流程

  • 判断键值对数组table是否为空或为null,否则执行resize()进行扩容(初始化);
  • 根据键值key计算hash值得到数组索引((n-1) & hash);
  • 如果 table[i]==null,直接新建节点添加;
  • 如果 table[i]!=null,
    • 判断table[i]的首个元素是否和key一样,如果相同直接覆盖value;
    • 判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对;
    • 遍历table[i],链表的尾部插入数据,然后判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操 作,遍历过程中若发现key已经存在直接覆盖value;
  • 插入成功后,判断实际存在的键值对数量size是否超过了最大容量 threshold(数组长度*0.75),如果超过,进行扩容。

注:扩容因子为0.75,即数组中存储数据量达到总容量的0.75出发扩容。


(3)扩容机制

  • 在添加元素或初始化的时候会调用resize方法进行扩容,首次添加数据初始化数组长度为16,以后每次每次扩容都是达到了扩容阈值(数组长度 * 0.75);
  • 每次扩容的时候,都是扩容之前容量的2
  • 扩容之后,会新创建一个数组,需要把老数组中的数据挪动到新的数组中;
    • 没有hash冲突的节点,则直接使用 e.hash & (newCap - 1) 计算新数组的索引位置;
    • 如果是红黑树,走红黑树的添加;
    • 如果是链表,则需要遍历链表,可能需要拆分链表。判断(e.hash & oldCap)是否为0,为0则停留在原始下标位置,不为0则移动到 原始位置+旧数组大小 这个位置上。

Q:为何HashMap的数组长度一定是2的次幂(2倍扩容)?

A:

(1)计算索引时效率更高:如果是 2 的 n 次幂可以使用位与运算代替取模;

(2)扩容时重新计算索引效率更高: hash & oldCap == 0 的元素留在原来位置 ,否则新位置 = 旧位置 + oldCap

注:oldCap表示旧数组长度。

Q:hashMap的寻址算法?

A:

(1)计算对象的 hashCode();

(2)再进行调用 hash() 方法进行二次哈希,hashcode值右移16位再异或运算,让哈希分布更为均匀;

(3)最后 (capacity – 1) & hash 得到索引。


(3)jdk1.7多线程情况下死循环问题

jdk1.7hashmap中在数组进行扩容的时候,因为链表是头插法,在进行数据迁移的过程中,有可能导致死循环

比如说,现在有两个线程

线程一:读取到当前的hashmap数据,数据中一个链表,在准备扩容时,线程二介入

线程二:也读取hashmap,直接进行扩容。因为是头插法,链表的顺序会进行颠倒过来。比如原来的顺序是AB,扩容后的顺序是BA,线程二执行结束。

线程一:继续执行的时候就会出现死循环的问题。

线程一先将A移入新的链表,再将B插入到链头,由于另外一个线程的原因,Bnext指向了A,所以B->A->B,形成循环。

当然,JDK 8 将扩容算法做了调整,不再将元素加入链表头(而是保持与扩容前一样的顺序),尾插法,就避免了jdk7中死循环的问题。


2、hashTable 与 hashMap 区别

1)继承的父类

HashMap继承自AbstractMap;HashTable继承自Dictionary类,该类已经被标记为废弃。

2)线程安全

hashTable线程安全,hashMap线程不安全;

3)解决hash冲突的方式

  • hashMap在1.7及之前,使用链表;1.8开始,在链表长度到 8 且数组长度到 64,转为红黑树;节点数减少到 6,转回链表;
  • hashTable使用链表。

4)扩容方式

hashMap 初始大小为16,2倍扩容;

hashTable 初始大小为11,2n+1;

5)是否允许null值;

HashMap键和值都运行为null;HashTable都不允许为null,否则会抛出空指针异常。


参考:

https://www.bilibili.com/video/BV1yT411H7YK

https://zhuanlan.zhihu.com/p/646536067 ;

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

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

相关文章

dolphinScheduler + hive + datax报错记录

1、参数错误 报错信息 [INFO] 2024-04-11 06:43:18.386 - [taskAppIdTASK-29-3301-84461]:[498] - after replace sql , preparing : insertoverwrite table mis_month partition (dt) select nvl(sl.slid , ) as id,--水量 IDnvl(sl.hh …

MongoDB教程(二):mongoDB引用shell

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、MongoD…

了解AsyncRotationController

概述 基于android 15.0, 以从强制横屏App上滑退回桌面流程来分析 frameworks/base/services/core/java/com/android/server/wm/AsyncRotationController.javaAsyncRotationController 是一种控制器&#xff0c;用于处理设备显示屏旋转时非活动窗口的异步更新。这种控制器通过…

设计模式——适配器设计模式

设计模式——适配器设计模式 适配器设计模式1.1 基本介绍1.2 工作原理1.3 类适配器模式1.3.1 基本介绍1.3.2 示例1.3.3 代码实现1.3.4 注意事项 1.4 对象适配器模式1.4.1 基本介绍1.4.2 示例1.4.3 代码实现1.4.4 注意事项 1.5 接口适配器模式1.5.1 基本介绍1.5.2 示例1.5.3 代码…

Splashtop 在医疗与制药领域的业务增长近五倍

2024年7月10日 加利福尼亚州库比蒂诺 Splashtop 是安全远程访问和 IT 支持解决方案领域的领先企业&#xff0c;该公司今天宣布&#xff0c;在医疗与制药领域业务同比增长492%&#xff0c;取得了里程碑式的成就。快速发展的数字实验室环境和持续的网络安全威胁需要实施无缝、安…

Unity之VS脚本自动添加头部注释Package包开发

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之VS脚本自动添加头部注释Package包开发 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&…

uniapp启动图延时效果,启动图的配置

今天阐述uniapp开发中给启动图做延迟效果&#xff0c;不然启动图太快了&#xff0c;一闪就过去了&#xff1b; 一&#xff1a;修改配置文件&#xff1a;manifest.json "app-plus" : {"splashscreen" : {"alwaysShowBeforeRender" : false,"…

法律咨询援助网站

1 项目介绍 1.1 摘要 随着互联网技术的飞速发展&#xff0c;公众对于便捷、高效的法律咨询服务需求日益增长。传统的法律咨询方式已难以满足人们即时性、多样化的咨询需求&#xff0c;促使法律咨询援助网站应运而生。这些平台旨在通过数字化手段&#xff0c;为用户提供法律知…

apache:the requested operation has failed使用httpd -t

Apache24\bin cmd 回车 httpd -t 因为我重新压缩了&#xff0c;记住&#xff0c;重新压缩要使用原路径&#xff0c; 因为你安装的 时候使用的是原路径 还是不行就改个端口&#xff0c;切记修改配置文件httpd.conf先把Tomcat停了 Define SRVROOT "F:\Apache\Apache24&q…

C++类和对象学习笔记

1.类的定义 1.1类定义的格式 class是定义类的关键字&#xff0c;Date为类的名字&#xff0c;{ }中为类的主体&#xff0c;注意定义类结束时后面的分号不能省略。类中的内容称为类的成员&#xff1b;类中的变量称为类的属性或成员变量&#xff1b;类中的函数称为类的方法或者成…

自定义枚举对象序列化规则: 在Json中以枚举的code值表示枚举;枚举序列化时,新增枚举描述字段;String到IEnum的转换

文章目录 引言I 案例分析1.1 接口签名计算1.2 请求对象1.3 枚举对象序列化1.4 创建JavaTimeModule以支持Java 8的时间日期类型序列化和反序列化1.5 请求对象默认值处理II 在JSON中以枚举的code值来表示枚举的实现方式2.1 自定义toString方法返回code2.2 使用@JsonValue注解,只…

adminPage-vue3依赖FormPage说明文档,表单页快速开发,使用思路及范例(Ⅱ)formConfig基础配置项

adminPage-vue3依赖FormPage说明文档&#xff0c;表单页快速开发&#xff0c;使用思路及范例&#xff08;Ⅱ&#xff09;formConfig配置项 属性: formConfig&#xff08;表单项设置&#xff09;keylabelnoLabeldefaultValuebindchildSlottypeString类型数据&#xff08;除 time…

IntelliJ IDEA 2024.1.4最新教程!!直接2099!!爽到飞起!!

IntelliJ IDEA 2024.1.4最新破解教程&#xff01;&#xff01;直接2099&#xff01;&#xff01;爽到飞起&#xff01;&#xff01;【资源在末尾】安装馆长为各位看官准备了多个版本&#xff0c;看官可根据自己的需求进行下载和选择安装。https://mp.weixin.qq.com/s/Tic1iR_Xc…

【鸿蒙学习笔记】关系型数据库概述

目录标题 关系型数据库的运行机制样例代码共通方法 DBUtilsIndex 代码效果 关系型数据库的运行机制 1、 关系型数据库对应用提供通用的操作接口&#xff0c;底层使用SQLite作为持久化存储引擎&#xff0c;支持SQLite具有的数据库特性&#xff0c;包括但不限于事务、索引、视图…

自建邮件服务器有哪些方法步骤与注意事项?

自建邮件服务器如何设置解析&#xff1f;邮件服务器怎么使用&#xff1f; 自建邮件服务器可以为个人或企业提供更多的灵活性和控制权&#xff0c;然而&#xff0c;这也是一个复杂且需要谨慎处理的任务。AokSend将探讨自建邮件服务器的基本方法步骤和需要注意的事项。 自建邮件…

逻辑回归(纯理论)

1.什么是逻辑回归&#xff1f; 逻辑回归是一种常用的统计学习方法&#xff0c;主要用于解决分类问题。尽管名字中包含"回归"&#xff0c;但它实际上是一种分类算法 2.为什么机器学习需要使用逻辑回归 1.二元分类 这是逻辑回归最基本和常见的用途。它可以预测某个事…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【HMAC(C/C++)】

HMAC(C/C) HMAC是密钥相关的哈希运算消息认证码&#xff08;Hash-based Message Authentication Code&#xff09;&#xff0c;是一种基于Hash函数和密钥进行消息认证的方法。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生…

计算机SCI期刊,闭眼投,保证检索,命中率100%

一、期刊名称 Pervasive and Mobile Computing 二、期刊简介 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机 影响因子&#xff1a;3 中科院分区&#xff1a;3区 三、期刊简介 Pervasive and Mobile Computing Journal &#xff08;PMC&#xff09; 是一本高影响力…

基于前馈神经网络 FNN 实现股票单变量时间序列预测(PyTorch版)

前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记…

自定义View-渐变TextView(重点:绘制文本)

源码链接 夸克网盘分享 效果展示 分析 动态效果&#xff0c;使用Animator实现自定义View 继承TextView使用TextView的测量&#xff0c;不重写使用TextView的布局&#xff0c;不重写绘制-重写绘制 使用两种颜色绘制文本颜色占比不同&#xff0c;百分比从0~1 实现 自定义属性…