【Java八股面试系列】Arraylist和HashMap的底层原理

文章目录

    • ArrayList源码
      • 总:
      • 构造方法
      • 扩容机制
      • remove
    • HashMap
      • 总:
        • 构造方法
        • 细节问题
        • putVal()方法
        • resize()方法
        • Hash值
      • HashMap常见问题
    • ConcurrentHashMap
      • 总:
        • putVal()方法
        • 自己的测试
    • 为什么重写HashCode和equals

ArrayList源码

总:

**ArrayList**底层是使用名为 **elementDataObject动态数组进行实现,与Java中的数组相比,她的容量能够动态的进行增长。在我们更新元素的时候,我们会通过ensureCapacityInternal()方法来确保我们的容量够用,如果容量不够则调用grow()**方法对我们的数组进行扩容为1.5倍,然后将我们原来的的数组复制过去。

ArrayList 和 Vector 的区别?

  • ArrayListList 的主要实现类,底层使用 Object[]存储,适用于频繁的查找工作,线程不安全 。
  • VectorList 的古老实现类,底层使用Object[] 存储,线程安全。

ArrayList 可以添加 null 值吗?

ArrayList 中可以存储任何类型的对象,包括 null 值。不过,不建议向ArrayList 中添加 null 值, null 值无意义,会让代码难以维护比如忘记做判空处理就会导致空指针异常。

Arraylist 与 LinkedList 区别?

Arraylist 和 LinkedList都是实现了 List接口,都是线程不安全的。

不同点:

  • Arraylist底层是通过object数组进行实现,而LinkedList底层是通过双向链表进行实现
  • AL实现了随机读取接口,能够随机进行读取,用来查询的效率高,LL不能进行随机读取,只能遍历进行读取,但是她的插入效率高
  • 内存空间的占用上,AL的预留空间会占用一定的位置,而LL会占用更多的空间,因为要保存其他的一些位置信息

构造方法

Arraylist有有参构造方法也有无参构造方法,有参的构造方法会将我们的容器大小设置为设置的大小

无参构造方法先是将提前创建好的空数组给他,后续使用的时候在进行扩容操作

扩容机制

这里每次add操作的时候都会使用ensure CapacityInternal()方法进行容量判断,如果不足则会使用grow进行扩容

在这里插入图片描述

private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

这里的calculate Capacity方法主要是判断容器是否是已经初始化过

private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;
}

这里计算所需的最小容量是否大于当前的容器容量

private void ensureExplicitCapacity(int minCapacity) {// 用来记录遍历的时候时候,集合有没有进行改变modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);
}

这里先将数组扩容为原来的1.5倍,判断是否够用,或者有没有超过最大的容量

private void grow(int minCapacity) {// overflow-conscious codeint 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);
}

hugeCapacity()方法 当我们容量超过了当前容器设置的最大值的时候执行

    private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?	// 这里的MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;Integer.MAX_VALUE :MAX_ARRAY_SIZE;}

如果不够的话,也只能最多再添加8个了

remove

Arraylist 集合移除元素时候执行的函数,然后使用 **System.arraycopy()**方法将数组进行复制再将原来位置设置为null方便进行 gc

public E remove(int index) {rangeCheck(index); // 判断移除的元素是否越界modCount++;  // 判断当前的集合是否被修改E oldValue = elementData(index);int numMoved = size - index - 1;	// 确定移除位置if (numMoved > 0)	System.arraycopy(elementData, index+1, elementData, index, numMoved);  elementData[--size] = null; // clear to let GC do its workreturn oldValue;
}

HashMap

总:

HashMap在 jdk1.8之前是由Node数组+链表组成的,在jdk1.8以后更改了解决hash冲突的方式,是由Node数组+链表或者红黑树实现。元素添加是通过**putVal()方法添加,HashMap通过扰动函数处理得到Hash值,如果发生hash冲突的时候就会先判断当前节点的链表大小如果超过8,然后调用treeifBin()**如果hashMap总的容量大于64则会转为红黑树进行存储。

为什么不使用多路平衡二叉树?

  1. 红黑树是一种平衡二叉树,多路平衡二叉树需要存储更多的节点信息,空间上会使用更多的空间
  2. 操作的复杂性,红黑树不是严格的平衡二叉树,两边子节点的高度差没有完全的差1,插入的时候更好的处理
  3. 红黑树的查询表现已经可以了,不需要多路平衡二叉树的B+树的范围查询了
构造方法

构造方法有三个,关键就是携带参数的问题,有没有 **initialCapacity初始化容量**和 loadFactor扩容阈值

细节问题

默认的大小是16,AL是10,扩容每次为一倍,AL每次扩容1.5倍

putVal()方法

在这里插入图片描述

resize()方法

计算出新的**Capacity**和 threshold的值,然后创建一个新的数组,将我们原来的数组的值复制进去

**threshold**的值是通过 Capacity的值与设置的阈值0.75相乘得出来的

Hash值

hashCode()方法返回的是int整数类型,其范围为


-(2 ^ 31)~(2 ^ 31 - 1),而HashMap的容量范围是在16(初始化默认值)~2 ^ 30,HashMap通常情况下是取不到最大值的,并且设备上也难以提供这么多的存储空间,从而导致通过hashCode()计算出的哈希值可能不在数组大小范围内,进而无法匹配存储位置;

那怎么解决呢?

HashMap自己实现了自己的hash()方法,通过两次扰动使得它自己的哈希值高低位自行进行异或运算,降低哈希碰撞概率也使得数据分布更平均;
在保证数组长度为2的幂次方的时候,使用hash()运算之后的值与运算(&)(数组长度 - 1)来获取数组下标的方式进行存储,这样一来是比取余操作更加有效率,二来也是因为只有当数组长度为2的幂次方时,h&(length-1)才等价于h%length,三来解决了“哈希值与数组大小范围不匹配”的问题;

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

HashMap常见问题

为什么线程不安全

因为可能会造成数据丢失的问题,假如两个线程同时进行插入,并且产生了Hash碰撞,那么线程1判断完成以后插入之前挂起,同时线程2进行插入,这时线程1插入的将会覆盖线程2

ConcurrentHashMap

总:

ConcurrentHashMap是一个并发容器,能够解决多个线程使用HashMap造成的线程安全问题,底层的**putVal函数**是通过 Cas操作和Synchronized操作来保证线程的安全性。其他的结构和HashMap一样。

putVal()方法

和HashMap的过程基本一致

只是如果计算出hash值原位置没有的话,直接使用cas操作进行插入

如果后续碰撞则使用synchronized进行插入

自己的测试

自己使用了四个线程,分别进行100万次随机位置的写入,查看每个线程的完成时间,平均每个线程的完成时间将会降低百分之30左右。

为什么重写HashCode和equals

因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。

如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。

思考:重写 equals() 时没有重写 hashCode() 方法的话,使用 HashMap 可能会出现什么问题。

总结

  • equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。
  • 两个对象有相同的 hashCode 值,他们也不一定是相等的(哈希碰撞)。

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

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

相关文章

3.28号arm

can总线相关理论 1. 概念 控制器局域网&#xff08;Controller Area Network&#xff0c;CAN&#xff09;&#xff0c;其特点是可拓展性好&#xff0c;可承受大量数据的高速通信&#xff0c;高度稳定可靠&#xff0c;因此常应用于汽车电子领域、工业自动化、医疗设备等高要求…

Java JSON字符串相关问题

一、依赖包 <!--json包--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.15</version></dependency> 二、举例 1.实体对象转Json字符串 1.1 代码实现 Dog.java: pack…

python_web1(前端开发之HTML、CSS、Bootstap、Javascript、JQuery)

文章目录 一、Flask网页开发1.1创建一个名为web1.py的python文件1.2 templates目录创建文件index.html 二、html标签2.1 编码2.2title < head >2.3 标题< h>2.4 div和span2.5超链接1.在index.xml文件中补充。2.修改web1.py文件3.添加get_self.html4.效果 2.6图片1.…

Java 堆外内存及调优

文章目录 直接内存简介为什么DirectByteBuffer可以优化 IO 性能 直接内存的分配直接内存的回收直接内存跟踪与诊断 直接内存简介 直接内存(Direct Memory) 并不是虚拟机运行时数据区的一部分&#xff0c;并非Java虚拟机规范中定义的内存区域。但是这部分内存的频繁使用&#x…

【LeetCode】三月题解

文章目录 [2369. 检查数组是否存在有效划分](https://leetcode.cn/problems/check-if-there-is-a-valid-partition-for-the-array/)思路&#xff1a;代码&#xff1a; [1976. 到达目的地的方案数](https://leetcode.cn/problems/number-of-ways-to-arrive-at-destination/) 思路…

C++教学——从入门到精通 5.单精度实数float

众所周知&#xff0c;三角形的面积公式是(底*高)/2 那就来做个三角形面积计算器吧 到吗如下 #include"bits/stdc.h" using namespace std; int main(){int a,b;cin>>a>>b;cout<<(a*b)/2; } 这不对呀&#xff0c;明明是7.5而他却是7&#xff0c;…

让IIS支持.NET Web Api PUT和DELETE请求

前言 有很长一段时间没有使用过IIS来托管应用了&#xff0c;今天用IIS来托管一个比较老的.NET Fx4.6的项目。发布到线上后居然一直调用不同本地却一直是正常的&#xff0c;关键是POST和GET请求都是正常的&#xff0c;只有PUT和DELETE请求是有问题的。经过一番思考忽然想起来了I…

YOLOv9改进策略 :主干优化 | 极简的神经网络VanillaBlock 实现涨点 |华为诺亚 VanillaNet

💡💡💡本文改进内容: VanillaNet,是一种设计优雅的神经网络架构, 通过避免高深度、shortcuts和自注意力等复杂操作,VanillaNet 简洁明了但功能强大。 💡💡💡引入VanillaBlock GFLOPs从原始的238.9降低至 165.0 ,保持轻量级的同时在多个数据集验证能够高效涨点…

每日学习笔记:C++ STL算法分类

非更易型 更易型 移除型 变序型 排序型 已排序区间算法 数值型算法

【滑动窗口】Leetcode 将 x 减到 0 的最小操作数

题目解析 1658. 将 x 减到 0 的最小操作数 算法讲解 这道题按照题目要求的话会变得很难&#xff0c;因为不仅需要考虑数字减到0&#xff0c;还需要考虑最小的操作数。正难则反&#xff0c;按照这个思路&#xff0c;我们来解析题目 这道题本质上无非就是在左边寻找一段区间&a…

HCIP第三次作业(综合)

一、实验要求 二、实验步骤 1、配置IP地址部分 PC1&#xff1a; PC2&#xff1a; PC3&#xff1a; PC4&#xff1a; R1&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a; R5&#xff1a; 环回&#xff1a; 2.通过配置缺省路由让公网互通 [R1]ip route-static 0.0.…

代码随想录第27天| 39. 组合总和

39. 组合总和 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 带你学透回溯算法-组合总和&#xff08;对应「leetcode」力扣题目&#xff1a;39.组合总和&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili 给你一个 无重复元…

思考:开启MMU瞬间可能出现的多种问题以及多种解决方案

快速链接: 【精选】ARMv8/ARMv9架构入门到精通-[目录] &#x1f448;&#x1f448;&#x1f448; (说明本文的介绍都是基于armv8-aarch64或armv9硬件架构) 在mmu未开启阶段&#xff0c;PC操作的都是物理地址执行程序&#xff0c;这样看起来一切正常&#xff0c;没啥问题。 例如…

Windows Server 2022 使用ApacheDS用户远程桌面登录服务器

Windows Server 2022 使用ApacheDS用户远程桌面登录服务器 1、接上篇 Windows Server 2022 使用ApacheDS用户认证 使用Administrator用户远程登录192.168.1.100windows server&#xff0c;打开pGina软件 2、输入刚刚在ApacheDS中的新添加的用户测试一下&#xff0c;会自动添加…

如何在极狐GitLab 配置 邮件功能

本文作者&#xff1a;徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了在极狐GitLab 用户…

【带你了解下前端开发语言有那些】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

爱上数据结构:二叉树的基本概念

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;数据结构 ​ 一、树的基本概念 1.概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起…

计算机网络数据链路层知识总结

物理层知识总结传送门 计算机网络物理层知识点总结-CSDN博客 功能 功能概述 一些基本概念 结点:主机、路由器链路﹔网络中两个结点之间的物理通道&#xff0c;链路的传输介质主要有双绞线、光纤和微波。分为有线链路、无线链路。数据链路︰网络中两个结点之间的逻辑通道&a…

Prometheus+grafana环境搭建rabbitmq(docker+二进制两种方式安装)(二)

搭建完Prometheusgrafana基础环境后参见&#xff1a;Prometheusgrafana环境搭建方法及流程两种方式(docker和源码包)(一)-CSDN博客&#xff0c;对我本地的一些常用法人服务进行一个监控。基本都可以根据官方文档完成搭建&#xff0c;因为docker和二进制方式安装各有优缺点。 d…

隐私计算实训营学习七:隐语SCQL的架构详细拆解

文章目录 一、SCQL Overview1.1 SCQL背景1.2 SCQL Overview 二、SCQL CCL三、SCQL架构 一、SCQL Overview 1.1 SCQL背景 SCQL&#xff1a;属于隐私计算BI范畴&#xff0c;允许多个互不信任参与方在不泄露各自隐私数据的条件下进行联合数据分析。 如下数据在不同机构&#xf…