ArrayList 和 HashMap 源码解析

1、ArrayList

1.1、ArrayList 构造方法

无参创建一个 ArrayList 数组默认为空数组

transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private int size; // 数组容量大小

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

指定数组大小 创建一个 ArrayList 数组默认为 指定大小,
如果 initialCapacity == 0 默认为空数组
如果 initialCapacity < 0 则会抛出异常

transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

1.2、add 方法

1、判断数组是否为空,为空则扩容为10,然后修改次数加1,添加数据到数组
2、不为空,则获取扩容大小(原数组大小 + 原数组右移1位),相当于扩容为原来的1.5倍,判断扩容后若小于当前需要的容量,则扩容为当前需要容量大小,然后修改次数加1,添加数据到数组
3、不为空,则扩容(原数组大小 + 原数组右移1位),相当于扩容为原来的1.5倍,判断扩容后若不小于当前需要的容量,则1.5倍扩容,然后修改次数加1,添加数据到数组
4、第四重则是判断是否超过 Integer.MAX_VALUE,2的31次方-1.若是则抛出异常 OutOfMemoryError

  • 扩容机制:默认大小为0,在新增的时候才会扩容,正常情况默认扩容为原来的1.5倍,然后会重新创建一个1.5倍大小的数组,再把原来数组上面的数据复制到新数组上面。

第二种情况只有设置数组初始容量为1时,才会发生。因为 1 >> 1 = 0;这时扩容时才会出现扩容后的比需要的小,才会进入 if (newCapacity - minCapacity < 0) 中

	public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // size 是当前数组大小,目前是0,传入1
        elementData[size++] = e;
        return true;
    }

	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); // 为空则返回一个大的值,10 和 1,10比较大,所以返回10
        }
        return minCapacity;
    }
    
	private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = 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);
    }

总结:
ArrayList 底层基于数组实现,查询快O(1),新增修改慢O(n),
查询基于索引,新增删除可能涉及到索引移位,新增还会涉及扩容
数组的元素都是连续存储的,这意味着在内存中,数组的元素之间是相邻的

2、LinkedList

LinkedList 是一个双向链表结构,每个节点是一个 node 节点,如下:
item 中存储的是数据,next存储的是下一个node节点的地址,prev存储的是上一个node节点的地址

private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

LinkedList 提供了针对头尾节点的操作,使得对头尾节点的 增删查 较快
在这里插入图片描述
总结:

LinkedList 底层基于双向链表结构,增删快O(1),查询慢O(n)。
链表中的节点并不一定是在内存中连续存放的。每个节点实际上是一个对象,而对象在内存中是根据可用的空间分配的,因此它们不一定是连续的。LinkedList 中的节点通过引用(指针)来连接,而这些节点在内存中的位置是不连续的。

应用场景:

因为 removeFirst 会返回删除的元素,所以可以模拟 FIFO(先进先出)

1、可以用于设计队列
2、可以用于设计栈

3、HashMap

  1. 初始化的时候设置大小,因为扩容、重新计算hash值非常费时,建议为2的n次方。如果没有设置初始值默认为16(首次put时才会创建16的数组)
  2. jdk1.8以前是数组+单向链表,jdk1.8以后是数组+单向链表+红黑树
  3. HashMap 不是线程安全的,涉及到线程安全建议使用 ConcurrentHashMap
  4. 当链表长度等于8时,如果容量没有达到64,会先扩容。如果容量达到了64,链表会转为红黑树。当红黑树节点小于6个时会转为链表
  5. 数组为Node类型,在jdk7中称为Entry类型
  6. 链表时间复杂度为O(n),红黑树为O(logn)

3.1、HashMap 扩容机制

扩容是为了减少哈希冲突,提高存取效率。
HashMap 负载因子默认为 0.75

  1. 当临界值 > HashMap数组长度 * 0.75 就会进行扩容
  2. 当链表长度为8,HashMap数组长度小于64,就会进行扩容

hashmap扩容时会创建一个原数组两倍大的数组,然后遍历原数组,将原来所有的数据都移到新数组中。扩容之后需要重新hash,因为哈希值 = hashcode % (length -1),扩容后长度改变,hash值也会随之改变。

3.2、Node节点

哈希值(hash)、键(key)、值(value)以及指向下一个节点的引用(next)。
在 HashMap 的实现中,存储的键值对数据结构是通过链表来实现的。每个 Node 对象就是链表中的一个节点,通过 next 引用指向下一个节点。这样就可以处理哈希冲突,因为具有相同哈希值的键值对会放在同一个哈希桶中,通过链表进行连接。当链表长度达到一定阈值时,会将链表转换为红黑树以提高查询效率。

Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

3.3、负载因子

为什么负载因子是0.75呢?

参数的设置是经过实际测试和经验得出的。加载因子的选择需要权衡空间和时间效率,
过小的加载因子会导致哈希表频繁扩容,
而过大的加载因子会导致链表过长,查找效率下降。
因此,0.75 是一个比较合理的折衷选择,可以在空间和时间上实现比较好的性能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot校园车辆管理系统

背景 伴随着社会经济的快速发展&#xff0c;机动车保有量不断增加。不断提高的大众生活水平以及人们不断增长的自主出行需求&#xff0c;人们对汽车的 依赖性在不断增强。汽车已经发展成为公众日常出行的一种重要的交通工具。在如此形势下&#xff0c;高校校园内的机动车数量也…

java设计模式学习之【原型模式】

文章目录 引言原型模式简介定义与用途实现方式UML 使用场景优势与劣势原型模式在spring中的应用员工记录示例代码地址 引言 原型模式是一种创建型设计模式&#xff0c;它允许对象能够复制自身&#xff0c;以此来创建一个新的对象。这种模式在需要重复地创建相似对象时非常有用…

近五年—中国十大科技进展(2018年—2022年)

近五年—中国十大科技进展&#xff08;2018-2022&#xff09; 2022年中国十大科技进展1. 中国天眼FAST取得系列重要进展2. 中国空间站完成在轨建造并取得一系列重大进展3. 我国科学家发现玉米和水稻增产关键基因4. 科学家首次发现并证实玻色子奇异金属5. 我国科学家将二氧化碳人…

Vue 定义只读数据 readonly 与 shallowReadonly

readonly 让一个响应式数据变为 **深层次的只读数据**。 shallowReadonly 让一个响应式数据变为 **浅层次的只读数据**&#xff0c;只读第一层。 isReadonly 判断一个数据是不是只读数据。 应用场景&#xff1a;不希望数据被修改时使用。 readonly深层次只读&#xff1a; …

读像火箭科学家一样思考笔记12_实践与测试(下)

1. 舆论的火箭科学 1.1. 如果苹果违反了“即飞即测”原则&#xff0c;那苹果的iPhone就不会问世了 1.1.1. iPhone在其上市前的民意调查中相当失败 1.1.1.1. iPhone不可能获得太大市场份额&#xff0c;不可能。 1.1.1.1.1. 微软前CEO史蒂夫鲍尔默&#xff08;Steve Ballmer&…

msng病毒分析

这是一个非常古老的文件夹病毒&#xff0c;使用XP系统的文件夹图标&#xff0c;采用VB语言开发&#xff0c;使用了一种自定义的壳来保护&#xff0c;会打开网址http://www.OpenClose.ir,通过软盘、U盘和共享目录进行传播&#xff0c;会在U盘所有的目录下生成自身的副本&#xf…

采集工具-免费采集器下载

在当今信息时代&#xff0c;互联网已成为人们获取信息的主要渠道之一。对于研究者和开发者来说&#xff0c;如何快速准确地采集整个网站数据是至关重要的一环。以下将从九个方面详细探讨这一问题。 确定采集目标 在着手采集之前&#xff0c;明确目标至关重要。这有助于确定采集…

三季度营收下滑16.3%,网易云音乐如何讲出新故事?

在选择重新回归音乐本身后&#xff0c;网易云音乐(09899.HK)业绩承压的困局写在最新的三季报里。 「不二研究」据网易云音乐三季报发现&#xff1a;今年三季度&#xff0c;网易云音乐净收入同比下滑16.3%。目前&#xff0c;网易云音乐主要面临营收下滑、商业化场景探索尚未形成…

MSB3541 Files 的值“<<<<<<< HEAD”无效。路径中具有非法字符。

MSB3541 Files 的值“<<<<<<< HEAD”无效。路径中具有非法字符。 一般来说出现这个问题是因为使用git版本控制工具合并代码出现了问题&#xff0c;想要解决也很简单。 如图点击错误后定位到文件&#xff0c;发现也没有什么问题。 根据错误后边的提示&a…

前后端分离开发出现的跨域问题

先说说什么是跨域。 请求的URL地址中的协议、域名、端口号中的任意一个与当前URL不同就是跨域。 比如&#xff1a; 当前页面的URL请求的URL是否跨域原因htttp://localhost:8080htttps://localhost:8080是协议不同htttp://localhostll:8080htttp://localhost:8080是域名不同htt…

JVM 内存结构

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

【赠书第9期】巧用ChatGPT高效搞定Excel数据分析

文章目录 前言 1 操作步骤 1.1 数据清理和整理 1.2 公式和函数的优化 1.3 图表和可视化 1.4 数据透视表的使用 1.5 条件格式化和筛选 1.6 数据分析技巧 1.7 自动化和宏的创建 2 推荐图书 3 粉丝福利 前言 ChatGPT 是一个强大的工具&#xff0c;可以为你提供在 Exce…

【Newman+Jenkins】实施接口自动化测试

一、是什么Newman Newman就是纽曼手机这个经典牌子&#xff0c;哈哈&#xff0c;开玩笑啦。。。别当真&#xff0c;简单地说Newman就是命令行版的Postman&#xff0c;查看官网地址。 Newman可以使用Postman导出的collection文件直接在命令行运行&#xff0c;把Postman界面化运…

链接2:静态链接、目标文件、符号和符号表

文章目录 静态链接符号解析 (symbolresolution)重定位 (relocation) 目标文件1.可重定位目标文件2.可执行目标文件3.共享目标文件 可重定位目标文件text:rodata:.data.bss.symtab.rel.text.rel.data:debug:line:strtab: 符号和符号表由m定义并能被其他模块引用的全局符号由其他…

【用unity实现100个游戏之17】从零开始制作一个类幸存者肉鸽(Roguelike)游戏3(附项目源码)

文章目录 本节最终效果前言近战武器控制近战武器生成升级增加武器伤害和数量查找离主角最近的敌人子弹预制体生成子弹发射子弹参考源码完结 本节最终效果 前言 本节紧跟着上一篇&#xff0c;主要实现武器功能。 近战武器 新增Bullet&#xff0c;子弹脚本 public class Bull…

REST-Assured--JAVA REST服务自动化测试的Swiss Army Knife

什么是REST-Assured REST Assured是一套基于 Java 语言实现的开源 REST API 测试框架 Testing and validation of REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of using these languages into t…

Java第二十章多线程

一、线程简介 线程是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位。一个进程可以包含多个线程&#xff0c;这些线程可以并发执行。线程拥有自己的栈和局部变量&#xff0c;但是它们共享进程的其他资源&#xff0c;如…

STM32_10(I2C)

I2C通信 I2C&#xff08;Inter IC Bus&#xff09;是由Philips公司开发的一种通用数据总线两根通信线&#xff1a;SCL&#xff08;Serial Clock&#xff09;、SDA&#xff08;Serial Data&#xff09;同步&#xff0c;半双工带数据应答支持总线挂载多设备&#xff08;一主多从…

网络和信息系统指令 ( NIS2 ) 及其全球影响

网络和信息系统指令 ( NIS2 ) 将于 2024 年 10 月生效&#xff0c;旨在提高欧盟 (EU) 的网络弹性。 不过&#xff0c;其影响可能会更广泛&#xff0c;带来更严格的流程和控制&#xff0c;并重新定义我们向被视为国家关键的组织提供服务的方式。 该强制性指令将具有效力&#x…

如果每天工资按代码行数来算,来看看你每天工资是多少

说在前面 &#x1f63c;&#x1f63c;如果每天的工资取决于我们所编写的代码行数&#xff0c;那么我们的生活会发生怎样的改变&#xff1f;来看看你的同事们今天都提交了多少代码吧&#xff0c;看看谁是卷王&#xff0c;谁在摸鱼&#xff08;&#x1f436;&#x1f436;狗头保命…