JAVA之常用集合框架

java中的常用集合是对数据进行存储以及相关操作的api。常用的有ArrayList、LinkedList、Vector、HashSet、TreeSet、TreeMap、HashMap

ArrayList

数据结构

ArrayList的本质是一个数组 ,那么它就具有数组的所有特性 可以根据下标快速查找值

ArrayList是如何实现动态扩容的

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class accesspublic ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}

ArrayList的初始化就是一个空数组

第一次添加时   

    public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}

ensureCapacityInternal这个方法就是实现容量扩充的

    /*** Default initial capacity.*/private static final int DEFAULT_CAPACITY = 10;    private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}

可以看到 calculateCapacity该方法中初始将容量默认为10.那么是如何扩容的呢?我们知道这个方法ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))的入参是10了 接下来点进去看 

   private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)// minCapacity  为10   length此时为0grow(minCapacity);}
    private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;// oldCapacity 此时为0   二进制右移 然后加原值int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0) // newCapacity  就是10newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);}

由代码中的备注可以看出来 第一次添加oldCapacity  为0  所以最后newCapacity  为初始默认值10,也就是说 第一次添加后 数组的 容量变为10 ,长度为1。在不超过数组长度添加值时,数组不再进行扩容,那么当第十一次添加呢? oldCapacity  为数组length为10    10的二进制为1010 右移两位为0101  相加得1111 为15。当第16次添加时,为22  因此 ArrayList就是以原值得近似1.5倍扩容得  

LinkedList

LinkedList的本质是一个双向链表,那么它具有双向链表的所有特性

LinkedList的添加方法

  public boolean add(E e) {linkLast(e);return true;}
    void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++;}

第一次添加时,l为null,那么该节点就是first节点,第二次添加,last首先为第一次添加的节点Node的pre指向第一个节点。l.next指向新添加的节点,双向链表就构建完成了。

Vector为什么不推荐使用了?

Vector也是一个动态扩容的数组,跟ArrayList很类似,我们来看一个添加的方法。

    public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;}

与ArrayList几乎一摸一样,唯一不同的就是Vector的每个方法上都加了synchronized 关键字,每个方法都是同步的,这就导致了Vector的执行效率是很低的。但是如果有数据安全的问题,也可以考虑使用   List<String> strings = Collections.synchronizedList(Arrays.asList("1", "2"));  将LIst转换成线程安全的list

 public HashSet() {map = new HashMap<>();}

HashSet的本质就是一个HashMap

  public TreeSet() {this(new TreeMap<E,Object>());}

TreeSet的本质就是可以看到new了一个TreeMap

TreeMap是如何实现的?

TreeMap的本质就是一颗红黑树,提供一个红黑数在线网站,可以进行节点的添加删除等在线操作Red/Black Tree Visualization (usfca.edu)

treeMap首先定义了几个属性 左节点 右节点 父节点以及颜色 黑色。红黑树的根节点必须为黑色,接下来看一下TreeMap的添加操作

// 新增节点首先颜色初始化为红色 
x.color = RED;
//  新增节点非根节点 并且父节点为红色时while (x != null && x != root && x.parent.color == RED) {if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {Entry<K,V> y = rightOf(parentOf(parentOf(x)));if (colorOf(y) == RED) {setColor(parentOf(x), BLACK);setColor(y, BLACK);setColor(parentOf(parentOf(x)), RED);x = parentOf(parentOf(x));} else {if (x == rightOf(parentOf(x))) {x = parentOf(x);rotateLeft(x);}setColor(parentOf(x), BLACK);setColor(parentOf(parentOf(x)), RED);rotateRight(parentOf(parentOf(x)));}} else {Entry<K,V> y = leftOf(parentOf(parentOf(x)));if (colorOf(y) == RED) {setColor(parentOf(x), BLACK);setColor(y, BLACK);setColor(parentOf(parentOf(x)), RED);x = parentOf(parentOf(x));} else {if (x == leftOf(parentOf(x))) {x = parentOf(x);rotateRight(x);}setColor(parentOf(x), BLACK);setColor(parentOf(parentOf(x)), RED);rotateLeft(parentOf(parentOf(x)));}}}root.color = BLACK;

TreeMap的添加操作可以总结为上图 的几种情况,TreeMap底层就是对该红黑树的一个实现

 Hashmap

HashMap的底层结合了链表 红黑树 和hash的技术

HashMap是如何扩容的?

1.hashMap有两个构造参数,如果采用有参构造,给定了initialCapacity容量值,则会根据下面的代码取该给定值的 向上最接近2的幂的值

2. 如果没有给定值,则会取默认的初始值16

上述有参和无参的构造方法还会设置阈值,默认设置为0.75。如果当hashMap的entry数组长度大于阈值的时候,就会触发扩容,扩容是两倍的resize

HashMap是如何解决hash冲突的?

1.去拿hash值的时候,我们可以看到,利用了扰动函数会降低hash冲突

2。如果冲突了,hashMap首先会通过链式地址法解决冲突(也就是hash冲突的数值,放到已有数值的next链表后面),为图中的红色部分,直接挂在该节点后面。

那么黄色部分是干嘛得呢?TREEIFY_THRESHOLD默认值定义为7,也就是当该链表下面挂得数值大于等于7时,将该链表转换为红黑树

图中红色部分,将该链表转换为红黑树,会先判断该Map的size是否小于64,如果小于64,会执行resize方法进行扩容。否则,就将链表转为红黑树。

在resize方法中有这么一个方法,就是如果扩容后,数组下标的数的节点小于6了,会将红黑树重新转为链表,提高操作性能。

总结

ArrayList的本质就是一个1.5倍动态扩容的数组;LinkedList的本质就是一个双向链表的实现;Vector的本质就是每个方法都加了synchronized关键字的ArrayList.  两个Set TreeSet的本质就是TreeMap;HashSet的本质就是HashMap; TreeMap的本质就是一颗红黑树的实现;HashMap的是根据固定阈值进行两倍扩容。利用链式地址、红黑树的相互转换解决hash冲突的。

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

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

相关文章

路由器初始化配置、功能配置

实验环境 拓扑图 Ip规划表&#xff08;各组使用自己的IP规划表&#xff09; 部门 主机数量 网络地址 子网掩码 网关 可用ip Vlan 市场部 38 192.168.131.0 255.255.255.0 192.168.131.1 2-254 11 研发部 53 192.168.132.0 255.255.255.0 192.168.132.1 2-2…

弹性调度助力企业灵活应对业务变化,高效管理云上资源

作者&#xff1a;吴昆 什么是弹性调度 云计算时代&#xff0c;企业可以通过云平台获得大量计算资源&#xff0c;并根据业务发展和流量需求的实时变化&#xff0c;灵活调整使用的资源类型与资源量。阿里云提供了多种弹性资源&#xff0c;如云服务器 ECS 和弹性容器实例 ECI&am…

SpringBoot解决Slow HTTP慢速攻击漏洞

项目场景&#xff1a; 扫描到的漏洞截图&#xff1a; 攻击原理&#xff1a; Web应用在处理HTTP请求之前都要先接收完所有的HTTP头部&#xff0c;因为HTTP头部中包含了一些Web应用可能用到的重要的信息。攻击者利用这点&#xff0c;发起一个HTTP请求&#xff0c;一直不停的发送…

SpringCloud Aliba-Sentinel【上篇】-从入门到学废【4】

&#x1f3b5;诗词分享&#x1f3b5; 大江东去&#xff0c;浪淘尽&#xff0c;千古风流人物。 ——苏轼《念奴娇赤壁怀古》 目录 &#x1f37f;1.Sentinel是什么 &#x1f9c2;2.特点 &#x1f9c8;3.下载 &#x1f32d;4.sentinel启动 &#x1f953;5.实例演示 1.Senti…

Java代码审计Shiro反序列化CB1链source入口sink执行gadget链

目录 0x00 前言 0x01 CC链&CB链简介 1. Commons Collections链是什么&#xff1f; 2. Commons BeanUtils链是什么&#xff1f; 0x02 测试Commons BeanUtils1链 0x03 Shiro550 - Commons BeanUtils1链 - 跟踪分析&#xff08;无依赖&#xff09; 1. 前置知识 2. Co…

【每日一题】按分隔符拆分字符串

文章目录 Tag题目来源解题思路方法一&#xff1a;遍历方法二&#xff1a;getline 写在最后 Tag 【遍历】【getline】【字符串】【2024-01-20】 题目来源 2788. 按分隔符拆分字符串 解题思路 方法一&#xff1a;遍历 思路 分隔符在字符串开始和结束位置时不需要处理。 分隔…

设计模式设计原则——依赖倒置原则(DIP)

DIP&#xff1a;Dependence Inversion Principle 原始定义&#xff1a;High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions。 官…

【正点原子STM32】搭建开发环境(安装MDK和器件支持包、DAP仿真器和ST LINK仿真器、CH340串口驱动)

一、常用开发工具简介 MDKDAP 二、安装MDK 1、MDK简介2、如何获取MDK3、安装MDK和器件支持包 三、安装仿真器驱动 DAP仿真器免驱ST LINK仿真器驱动安装方法 ST LINK驱动及教程 四、安装CH340 USB虚拟串口驱动 1、安装CH340 USB虚拟串口驱动2、为什么要安装CH340 USB虚拟…

《WebKit 技术内幕》之八(2):硬件加速机制

2 Chromium的硬件加速机制 2.1 GraphicsLayer的支持 GraphicsLayer对象是对一个渲染后端存储中某一层的抽象&#xff0c;同众多其他WebKit所定义的抽象类一样&#xff0c;在WebKit移植中&#xff0c;它还需要具体的实现类来支持该类所要提供的功能。为了完成这一功能&#x…

蓝桥杯官网填空题(奇怪的分式)

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 上小学的时候&#xff0c;小明经常自己发明新算法。一次&#xff0c;老师出的题目是&#xff1a;1/4乘以8/5 小明居然把分子拼接在一起&#xff0c;分母拼接在一起&…

无法找到mfc100.dll的解决方法分享,如何快速修复mfc100.dll文件

在日常使用电脑时&#xff0c;我们可能会碰到一些系统错误提示&#xff0c;比如“无法找到mfc100.dll”的信息。这种错误通常会阻碍代码的执行或某些应用程序的启动。为了帮助您解决这一问题&#xff0c;本文将深入探讨其成因&#xff0c;并提供几种不同的mfc100.dll解决方案。…

【分享】MathWorks中国汽车年会:“软件定义汽车”

从软件赋能到软件定义&#xff0c;汽车行业不仅需要解决诸如错误发现滞后带来的高昂代价、功能融合所需的跨学科知识、功能安全与实施成本之间的权衡等老问题&#xff0c;也面临着新的挑战&#xff1a;软件复杂度的不断提升、利用数据驱动创造价值、人工智能的引入和实现、数字…

【从0上手cornerstone3D】如何加载nifti格式的文件

在线演示 支持加载的文件格式 .nii .nii.gz 代码实现 npm install cornerstonejs/nifti-volume-loader// ------------- 核心代码 Start------------------- // 注册一个nifti格式的加载器 volumeLoader.registerVolumeLoader("nifti",cornerstoneNiftiImageVolu…

Spark SQL函数定义

目录 窗口函数 SQL函数分类 Spark原生自定义UDF函数 Pandas的UDF函数 Apache Arrow框架基本介绍 基于Arrow完成Pandas DataFrame和Spark DataFrame互转 基于Pandas完成UDF函数 自定义UDF函数 自定义UDAF函数 窗口函数 分析函数 over(partition by xxx order by xxx [as…

如何在ubuntu22.04安装ROS2

ubuntu22.04安装ROS2 教程 选择对应版本进行安装设置编码添加源安装ROS2设置环境变量 运行ROS2 选择对应版本 通过官方网站&#xff0c;查询Ubuntu与ros对应的版本&#xff0c;版本不一致也会出现安装不成功。 https://wiki.ros.org/ROS/Installation 每一个都可以进行点击&a…

140:leaflet加载here地图(v2软件多种形式)

第140个 点击查看专栏目录 本示例介绍如何在vue+leaflet中添加HERE地图(v2版本的软件),并且含多种的表现形式。包括地图类型,文字标记的设置、语言的选择、PPI的设定。 v3版本和v2版本有很大的区别,关键是引用方法上,请参考文章尾部的API链接。 直接复制下面的 vue+leaf…

基于SpringBoot Vue高校失物招领系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

FPGA:我的零基础学习路线(2022秋招已上岸)持续更新中~

可内推简历&#xff0c;丝我即可 前言 初次接触FPGA是在2022年3月左右&#xff0c;正处在研二下学期&#xff0c;面临着暑假找工作&#xff0c;周围的同学大多选择了互联网&#xff0c;出于对互联网的裁员形势下&#xff0c;我选择了FPGA&#xff0c;对于硬件基础知识我几乎是…

SpringMVC获取参数与页面跳转

获取参数 第一种 直接当成方法的参数&#xff0c;需要与前台的name一致 相当于Request.getAttribute("username") Controller 第二种 使用对象接收 页面的name也要和对象的字段一致 创建一个对应的实体类 Controller 将参数更换为User对象就行 SpringMVC获取到…

【GNN】人大魏哲巍“青源Talk”图机器学习

目录 简介 图学习历史与应用 历史-哥尼斯堡七桥问题 图历史发展介绍 图神经网络 应用&#xff08;&#xff01;&#xff01;&#xff09; 图学习近期工作 概况 图卷积神经网络&#xff08;ICML&#xff0c;NIPS&#xff0c;KDD&#xff09; 大规模图神经网络&#xf…