当前位置: 首页 > news >正文

JAVA开发(数据类型String和HasMap的实现原理)

在JAVA开发中,使用最多的数据类型恐怕是String 和 HasMap两种数据类型。在开发的过程中我们每天都使用的不亦乐乎。但是相信很多人都没有考虑过String数据类型的实现原理或者说是在数据结构中的存储原理,还有一个就是是HashMap,也很少有人去了解。而且随着jdk版本的发展,这两个类型的实现都一直在优化,而不是一成不变的。有时候只有在找工作面试的时候被面试官问题,然后是一脸蒙蔽。每天都在用,也不用考虑它的原理啊。懂得用不就行了吗?这句话其实对其实也不对,对于实现业务来说,是已经足够了。但是对于对每一行代码做到极致的性能,很多东西还是需要知道它的原理。今天这一节就来梳理梳理String和HashMap的实现原理。

String数据类型:

无处不在的String类型。它位于java jdk 的lang包中,所以无需import就可以直接使用。从源码上看String是被final修饰的,所以它是不能被继承的。

 

	/** ID */private Integer id;/** 用户姓名 */private String userName;/** 登录名 */private String loginName;/** 密码 */private String password;public User() {super();}public User(Integer id, String userName, String loginName, String password) {super();this.id = id;this.userName = userName;this.loginName = loginName;this.password = password;}

由于其使用的广泛性,几乎在每一代的JDK优化升级中都存在对String的优化。

首先在JDK1.7中,我们都知道 String s = "maoheyeren";这个对象是存在常量池中的,JDK1.6的常量池位于方法区。但是到了JDK1.7,就讲常量池优化到了堆中,因为堆的内存更大,方便常量池的扩展。

在JDK1.8和JDK1.8以前,我们可以看一下源码,它的构造函数,可以知道String的下一层是使用char类型存储,但是到了JDK9就使用了byte[]存储,进行了优化减少了存储空间消耗。

 所以就是大家平时天天使用的String类型,也不是一层不变的!这个需要注意,算法的优化永无止境!

String对象的创建方式:

String s = "茅河野人是大神";
String s = new String ("茅河野人是大神")

 

String的源码,实现了序列化、Comparable以及CharSequence接口。

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {// 在JDK1.8中String的值使用char[]数组保存private final char value[];// 使用私有成员变量hash来缓存String的哈希值private int hash; // Default to 0// 构造方法public String(String original) {this.value = original.value;this.hash = original.hash;}public String(char value[]) {this.value = Arrays.copyOf(value, value.length);}...省略
}

 还有一个比较关心的问题String到底能存多长的数据。

查看String源代码返回长度的方法,int类型所能表示的最大范围为[0, 2^31-1],实际根据String的两种创建方式还有所不同。

1、使用String s = "茅河野人是大神";  方式创建对象时javac编译会校验字符串的长度,0xFFFF所能表示的最大长度为2^16=65536,因此这种方式创建的字符串长度会小于65536。而且CONSTANT_Utf8_info型常量的最大长度是是65535 - 1 = 65534个字节,若是中文字符,长度为65535 / 3字节。如果运行时方法区设置的比较小,实际长度可能达不到理论字节。
 

2、使用new关键字创建对象时,对象在堆内存中分配空间,调用系统的copyOf(),方法,所支持的理论最大长度为Integer.MAX_VALUE,2^31-1;实际情况受虚拟机和堆内存的大小限制。

HashMap数据类型:

HaspMap我们天天往里面put东西,put字符串,put对象,用的时候就get出来,也是从来没思考过里面的实现原理。

JDK1.8 之前 HashMap 的数据结构是 数组+链表 。数组是 HashMap 的主体,单向链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于等于阈值(默认为 8)时,且tab.length>=64时,将链表转化为红黑树,以减少搜索时间。
 注意,HashMap的底层数据结构中链表是单向链表,也就是只有next指针,没有prev指针。而LinkedHashMap维护了before、 after、head以及tail。

JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash值 判断当前元素存放的位置(这里的 n 指的是数组的长度)。

如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖;不相同就通过拉链法解决冲突。

hashcode的计算算法:

hash(Object key)–扰动函数
所谓扰动函数指的就是 HashMap 的 hash 方法。使用 hash 方法也就是扰动函数是为了防止一些实现比较差的 hashCode() 方法造成的碰撞,换句话说使用扰动函数之后可以减少碰撞。

先获得key的hashCode的值 h,然后 h 和 h右移16位 做异或运算。

实质上是把一个数的低16位与他的高16位做异或运算,因为在 (n - 1) & hash 的计算中,hash变量只有末x位会参与到运算。使高16位也参与到hash的运算能减少冲突。

JDK1.7之前的hashMap存储结构:

 

到了JDK1.8以后进行额优化,这一点经常有些找事情的面试官会问到。可以看出HashMap以链表的方式存储在数组中,到了JDK1.8以后,以红黑树的方式存储在数组中。

 

   static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next;Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}public final K getKey()        { return key; }public final V getValue()      { return value; }public final String toString() { return key + "=" + value; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}public final boolean equals(Object o) {if (o == this)return true;if (o instanceof Map.Entry) {Map.Entry<?,?> e = (Map.Entry<?,?>)o;if (Objects.equals(key, e.getKey()) &&Objects.equals(value, e.getValue()))return true;}return false;}}

 

相关文章:

JAVA开发(数据类型String和HasMap的实现原理)

在JAVA开发中&#xff0c;使用最多的数据类型恐怕是String 和 HasMap两种数据类型。在开发的过程中我们每天都使用的不亦乐乎。但是相信很多人都没有考虑过String数据类型的实现原理或者说是在数据结构中的存储原理&#xff0c;还有一个就是是HashMap&#xff0c;也很少有人去了…...

Hbase 映射到Hive

目录 一、环境配置修改 关闭掉hbase&#xff0c;zookeeper和hive服务 进入hive312/conf 修改hive-site.xml配置&#xff0c; 在代码最后添加配置 将hbase235的jar包全部拷贝到hive312的lib目录&#xff0c;并且所有的是否覆盖信息全部输入n&#xff0c;不覆盖 查看hive312下…...

14_MySQL视图

1. 常见的数据库对象2. 视图概述2.1 使用视图的好处视图一方面可以帮我们使用表的一部分而不是所有的表&#xff0c;另一方面也可以针对不同的用户制定不同的查询视图。比如&#xff0c;针对一个公司的销售人员&#xff0c;我们只想给他看部分数据&#xff0c;而某些特殊的数据…...

做程序界中的死神,斩魂刀始解

标题解读&#xff1a;标题中的死神&#xff0c;是源自《死神》动漫里面的角色&#xff0c;斩魂刀是死神的武器&#xff0c;始解是斩魂刀的初始解放形态&#xff0c;卐解是斩魂刀的觉醒解放形态&#xff0c;也是死神的大招。意旨做程序界中程序员的佼佼者&#xff0c;一步一步最…...

顺序表——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容是数据结构与算法里面的顺序表啦&#xff0c;在我看来&#xff0c;数据结构总体上是一个抽象的东西&#xff0c;关键还是要多写代码&#xff0c;下面&#xff0c;就让我们进入顺序表的世界吧 线性表 顺序表 线性表 线性表&…...

嵌入式Linux从入门到精通之第十六节:U-boot分析

简介 u-boot最初是由PPCBoot发展而来的,可以引导多种操作系统、支持多种架构的CPU,它对PowerPC系列处理器的支持最为完善,而操作系统则对Linux系统的支持最好目前已成为Armboot和PPCboot的替代品。 特点: 主要支持操作系统:Linux、NetBSD、 VxWorks、QNX、RTEMS、ARTOS、L…...

UART 串口通信

第18.1讲 UART串口通信原理讲解_哔哩哔哩_bilibili 并行通信 一个周期同时发送8bit的数据&#xff0c;占用引脚资源多 串行通信 串行通信的通信方式&#xff1a; 同步通信 同一时钟下进行数据传输 异步通信 发送设备和接收设备的时钟不同 但是需要约束波特率&#xff08;…...

【硬件】P沟道和N沟道MOS管开关电路设计

场效应管做的开关电路一般分为两种&#xff0c;一种是N沟道&#xff0c;另一种是P沟道&#xff0c;如果电路设计中要应用到高端驱动的话&#xff0c;可以采用PMOS来导通。P沟道MOS管开关电路PMOS的特性&#xff0c;Vgs小于一定的值就会导通&#xff0c;当Vgs<0,即Vs>Vg,管…...

中移杭研一面经历

文章目录 1、常用的Java元注解@Documented@Target@Retention@Override@Deprecated@Inherited@Repeatable@Native2、Java注解的原理3、spring boot starter开发过程1、原理浅谈2、大概步骤3、项目介绍1、常用的Java元注解 @Documented @Documented 是一个标记注解,没有成员变…...

如何成为一名全栈工程师:专业建议与技能要求

作为一名全栈工程师&#xff0c;你需要拥有跨越前端、后端、数据库等多个领域的技能&#xff0c;并能够将它们整合起来构建出完整的应用程序。因此&#xff0c;成为一名全栈工程师需要你掌握多种技术&#xff0c;具备较强的编程能力和系统设计能力。下面&#xff0c;我将从以下…...

MySQL架构篇

一、进阶学习环境说明 1.1 MySQL服务器环境 Linux虚拟机&#xff1a;CentOS 7 MySQL&#xff1a;MySQL5.7.30 在Linux服务器中安装MySQL&#xff1a; ps.如果有自己的云服务器&#xff0c;可忽略前两步&#xff0c;直接进行第三步 1.2 服务器日志文件说明 MySQL是通过文件系统对…...

Redhat7.6安装weblogic10.3.6(超详细,有图文)

一、环境 linux版本&#xff1a;Redhat 7.6 weblogic版本:WLS10.3.6 jdk版本&#xff1a;jdk1.8.0 下载网址&#xff1a;https://www.oracle.com/technetwork/middleware/weblogic/downloads/index.html 1.安装vsftpd服务&#xff0c;将部署环境使用JDK文件和wls服务文件…...

dashboard疏散主机提示报错:无法疏散主机...处理方法、openstack虚拟机状态卡在重启处理方法、openstack在数据库修改虚拟机状态的方法

文章目录dashboard疏散主机提示报错&#xff1a;无法疏散主机...处理方法报错说明【状态卡在reboot状态】解决方法【登录nova数据库修改虚拟机信息】首先获取nova数据库的密码登录nova数据库并做修改验证信息是否修改成功再次迁移并验证报错说明【虚拟机状态error也会导致疏散失…...

力扣:轮转数组(详解)

前言&#xff1a;内容包括&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3…...

Vue计算属性Computed

30. Vue计算属性Computed 1. 定义 Computed属性是Vue中的一个计算属性&#xff0c;是一种基于其它属性值计算而来的属性值&#xff0c;具有缓存机制&#xff0c;在依赖的属性值发生变化时会重新计算。 使用computed属性可以避免在模板中书写过多的计算逻辑&#xff0c;提高代…...

实验四:搜索

实验四&#xff1a;搜索 1.填格子 题目描述 有一个由数字 0、1 组成的方阵中&#xff0c;存在一任意形状的封闭区域&#xff0c;封闭区域由数字1 包围构成&#xff0c;每个节点只能走上下左右 4 个方向。现要求把封闭区域内的所有空间都填写成2 输入要求 每组测试数据第一…...

本地开发vue项目联调遇到访问接口跨域问题

本地开发vue项目联调遇到访问接口跨域问题 修改本地的localhost 一&#xff1a;按winr打开运行窗口&#xff0c;输入drivers &#xff0c;然后回车 二&#xff1a;打开etc文件夹&#xff0c;然后用记事本的方式打开里面的hosts文件&#xff0c; 三&#xff1a;这时我们就可…...

Vue键盘事件的使用

前言 在vue中&#xff0c;我们经常会用到键盘事件&#xff0c;不管是我们按下某个键&#xff0c;其实都是一次键盘事件的调用&#xff0c;下面就介绍下Vue中的键盘事件 先写一段代码&#xff0c;这里我选择的键盘事件是keyup,当然用keydown也是没问题的 问题来了&#xff0c;…...

抓包工具fiddler详细使用教程

各位做测试的同学想必对抓包工具fiddler并不陌生&#xff0c;但是很多同学可能没有总结过它的用法&#xff0c;下面我总结了fiddler一些常用的用法。 Web端抓包配置 打开Fiddler&#xff0c;Tools -> Fiddler Options -> HTTPS 配置完后记得要重启Fiddler 选中Decrpt …...

raspberry Pi 连接蓝牙(小爱同学)

参数valueraspberry pi MOdel4B&#xff0c;4Gbbluetooth MOdel小爱同学writeTime2023年 2月11日 下午13&#xff1a;14分raspberry System ModelLinux raspberrypi 5.15.61-v8 #1579 SMP PREEMPT Fri Aug 26 11:16:44 BST 2022 aarch64 GNU/Linux 连接蓝牙 请在小爱同学app上…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...