JDK9 的字符串底层原理是什么?

Java字符串处理:从基础原理到性能优化实战 字符串作为编程中最基础的数据类型,在Java中通过String类实现其特有的存储机制与不可变性。从技术原理看,字符串常量池和UTF-16编码设计保障了内存效率与编码一致性,而StringBuilder等工具类则解决了频繁修改时的性能瓶颈。在实际工程中,字符串操作广泛存在于用户输入校验、文本解析、数据格式化等场景,合理运用intern()方法和预编译正则表达式能显著提升系统性能。针对Java字符串特有的内存管理和线程安全问题,深入理解其不可变特性和JDK7以后的堆内存分配机制尤为重要,这也是面试中常考察的St 阅读详情

前言

本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和文献引用请见100个问题搞定Java虚拟机

正文

在 Java 9 之前,字符串是用 char 数组来存储的,主要为了支持非英文字符。

然而,大多数 Java 程序中的字符串都是由 Latin1 字符组成的。

也就是说每个字符仅需占据一个字节,而使用 char 数组的存储方式将极大地浪费内存空间。

Java 9 引入了 Compact Strings 的概念,当字符串仅包含 Latin1 字符时,使用一个字节代表一个字符的编码格式,使得内存使用效率大大提高。

String#indexof 底层部分源码解析(JDK 11.0.11)

实际上 JDK9~JDK11 这部分源码未发生过变动,不过 JDK11 为 LTS 版本,我推荐使用 JDK11 来分析

/**
 * 在字符串 value 中查找字符串 str,注意 str 和 value 都是由 Latin1 字符构成,故底层都是用字节数组存储数据
 * @param value 原始字符串
 * @param str 待查找的字符串
 * @return 返回 value 中出现 str 的第一个索引值,返回 -1 说明找不到
 */
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, byte[] str) {
    // str 为空,则返回 0
    if (str.length == 0) {
        return 0;
    }
    // value 为空,返回 -1
    if (value.length == 0) {
        return -1;
    }
    return indexOf(value, value.length, str, str.length, 0);
}

/**
 * 在字符串 value 中查找字符串 str,注意 str 和 value 都是由 Latin1 字符构成,故底层都是用字节数组存储数据
 * @param value 原始字符串
 * @param valueCount 要查找的原始字符串数量 
 * @param str 待查找的字符串
 * @param strCount 待查找的字符串数量
 * @param fromIndex 从原始字符串的哪个索引值开始查找        
 * @return 返回 value 中出现 str 的第一个索引值,返回 -1 说明找不到
 */
@HotSpotIntrinsicCandidate
public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
    // 原始字符串的第一个字符
    byte first = str[0];
    int max = (valueCount - strCount);
    for (int i = fromIndex; i <= max; i++) {
        // 查找第一个字符
        if (value[i] != first) {
            while (++i <= max && value[i] != first);
        }
        if (i <= max) {
            // 这时候 i 代表 value 里面出现 str 第一个字符 所在的索引值
            int j = i + 1;
            // j 最多遍历到的索引值
            int end = j + strCount - 1;
            // j 一遍遍往右挪,如果挪到了 end 说明找到了目标字符串
            for (int k = 1; j < end && value[j] == str[k]; j++, k++);
            if (j == end) {
                // 找到了 str
                return i;
            }
        }
    }
    return -1;
}

关于 @HotSpotIntrinsicCandidate 可以参考我的这篇博客——HotSpot虚拟机中的intrinsic是指什么?

【一线大厂Java面试题合集】第02篇-String底层原理与字符串面试全集 Java核心基础 |:基础 |:★★★★★。 阅读详情

相关推荐

AutoCAD2016安装破解教程

AutoCAD2016安装破解教程。本人亲自实验,破解成功,有效。以64位为例。 工具/原料   笔记本电脑 AutoCAD2016安装包 AutoCAD2016注册机(xf-adsk2016_x64.exe)链接:http://pan.baidu.com/s/1cAZQA windows7/8/8.1/10-32...

weixin_33804990的博客 1万+

java indexof方法_indexOf原理,Java,javascript,python实现

简介最近做项目的时候,发现无论是前端还是后端,indexOf出现的概率都非常频繁,今天我们来看下他的实现原理吧!indexOf的含义:给定一个字符串去匹配另一个字符串的下标,如果匹配到,返回下标,如果匹配不到则返回-1,其实原理还是比较简单的,如果需要你实现,那么应该怎么做呢?原理现在给定匹配的字符串A,原始字符串B,比如匹配字符串A等于“叫练”,原始字符串B等于“边叫边练,我喜欢叫练”,你可能一...

weixin_39707201的博客 327

周立功CAN盒二次开发实录:用QT5.1.0解析汽车CAN报文(附数据可视化技巧)

本文详细介绍了基于QT5.1.0和周立功USBCAN-E-U设备进行汽车CAN总线二次开发的实战过程。核心内容包括利用CANdb++数据库解析原始报文并转换为物理值,以及通过QCustomPlot库实现高性能实时数据可视化,为车载诊断与车联网开发提供了一套完整的工程实践方案。

sugar的博客 1057

String 底层是如何实现的?

String底层是基于 char[ ] 数组或 byte[ ] 数组实现的,JDK9 之后,之所以使用 byte[ ] 替换 char[ ] 数组,这是因为,byte类型粒度更细,一个 char 等于 2 个 byte。对于大部分的英文字符和少量中文字符来说,使用 1 个 byte就够了,完全不需要使用 1 个 char 进行存储,所以 JDK9 使用 byte[ ] 之后,对于大部分英文字符来说,同样的内容,其存储空间减少了一半,这就是 JDK9 之后使用 byte[ ] 所带来的优势

dream_ready的博客 1016

x86架构学习之中断

外部中断,一般是由CPU的外部引脚电信号触发,这些引脚留给硬件厂商去定义中断,例如主板厂商可以将USB中断挂载70号中断引脚上,MCU厂商可以将片上外设(SPI、I2C等)的中断挂载在指定中断线上。中断描述符主要用于说明该中断的入口地址,中断描述符表则是将中断描述符一项一项管理在一个数组中,每一项中断描述符占用8个字节(64位模式下,占用16字节),其。简称中断,后文如果没特别说明,中断都指外部中断,由外部IO事件触发,由于时钟源来自CPU外部,与CPU时钟不同源,因此是异步事件。

qq_26962739的博客 1570

【光子 AI】AI Agent 知识体系深度研究报告

从理论基础到前沿应用:全面解析人工智能代理的核心架构、关键技术与发展趋势📅 2026 年 3 月 | 📊 深度研究报告 | 🔬 人工智能领域 | 📈 前沿技术分析**AI Agent(人工智能代理)**是一种能够感知环境、基于所获得的信息做出决策,并执行行动以影响该环境的软件系统。AI Agent 的设计旨在模仿或实现智能行为,它们可以在各种环境中操作,包括物理世界和虚拟空间。随着大语言模型(LLM)技术的突破性进展,AI Agent 正从实验室研究快速走向产业应用。根据 Gartner 发布的《2

AI天才研究院 176

JDK新特性(JDK9~JDK21)

该特性在java19中是预览版,虚拟线程是一种用户态下的线程,类似go语言中的goroutines 和Erlang中的processes,虚拟线程并非比线程快,而是提高了应用的吞吐量,相比于传统的线程是由操作系统调度来看,虚拟线程是我们自己程序调度的线程。如果你对之前java提供的线程API比较熟悉了,那么在学习虚拟线程的时候会比较轻松,传统线程能运行的代码,虚拟线程也可以运行。虚拟线程的出现,并没有修改java原有的并发模型,也不会替代原有的线程。虚拟线程主要作用是提升服务器端的吞吐量。

qq_22075913的博客 1314

微信小程序 - 真机调试请求异常 Provisional headers are shown,微信小程序开发者工具调试没问题就真机测试时出现请求报错(微信小程序请求接口提示Provisional h)

微信小程序开发 Request Headers: Provisional headers are shown,微信开发工具请求正常,真机调试和上线之后出现 Provisional headers are shown,微信小程序开发工具调试没问题,真机调试Provisional headers are shown,在开发工具调试,请求正常没问题,使用真机调试,请求异常,微信小程序真机调试时后台是本地服务器,显示“Provisional headers are shown”问题解决,微信小程序websocket

🏆 前端领域优质创作者 1万+

力扣 28.实现 strStr()

问题描述 实现 strStr() 函数。 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。 说明: 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。 示例1: 输入:haystack = "h

qq_43990947的博客 227

用 CL_ABAP_PARALLEL 把批量处理跑进并行对话进程:资源配额、超时治理与可复制的落地模板

文章摘要: CL_ABAP_PARALLEL是SAP推荐的并行处理工具,适用于时间窗口受限的批量任务处理。它基于aRFC/pRFC机制,通过对话进程实现并行,能将小时级任务压缩到分钟级。使用时需注意版本兼容性(可能需要Note 2791374)、资源限制(会话数、进程数)和任务切片策略。提供两种实现方式:继承式(重定义do方法)和接口式(实现IF_ABAP_PARALLEL)。关键参数包括并发控制(p_percentage)、超时设置(p_timeout)和调试开关(p_debug)。最佳实践建议按业务维度

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 240

服务器取证——服务器基础知识

服务器基础知识

记录并分享学习安全的知识点.. 2479

Java字符串String类操作方法整理

最近项目开发中要对文本进行处理,趁机整理下相关的方法 String类的基本操作,可分为以下几类:1、基本操作方法 2、字符串比较 3、字符串与其他数据类型之间的转换 4、字符与字符串的查找 5、字符串的截取与拆分 6、字符串的替换与修改 一、String基本操作方法 首先说一下基本操作方法,字符串的基本操作方法中包含以下几种:(1)获取字符串长度length()(2)获...

Jack__iT的博客 921

推理引擎终极对决:TensorRT vs ONNX Runtime,YOLOv8速度差30%的核心原因与实操指南

若你使用NVIDIA GPU,且追求极致速度和低延迟,TensorRT是唯一选择,尤其是边缘设备和实时场景;若你需要跨硬件部署、快速验证原型,或预算有限(无需NVIDIA GPU),ONNX Runtime是性价比之王;对于YOLOv8这类检测模型,TensorRT的FP16/INT8量化是“免费的速度提升”,建议优先采用。最后提醒:推理引擎的优化是“细节决定成败”——同样的引擎,不同的预处理方式、显存配置、批大小,都会导致10%-20%的性能差异。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1026

Java字符串的+底层原理

Java字符串的+底层原理

大连赵哥的博客 285

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【JVM】剖析字符串与数组的底层实现(二)

jdk8:底层是一个char[]数组jdk9及之后:底层是一个byte[]数组一个中文占两个字节,一个char占两个字节,一个byte占一个字节Jdk9及之后的版本中,多了一个code属性,这个属性标记是告诉调用者按几个字节来取的问题,如果按byte存储的话,存不是什么问题,问题是如何取呢?

Cover_sky的博客 1553

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java培训:String类的底层原理和版本演变

但是很多时候,一个字符只需要一个字节就可存储,比如各种字母什么的,两个字节存储势必会浪费空间,JDK9的一个优化就在这,内存的优化,所以JDK9之后字符串改成byte类型数组进行存储。在JDK9的String类中,新增了一个属性coder,它是一个编码格式的标识,使用LATIN1还是UTF16,这个是在String生成的时候自动确定的,如果字符串中都是能用LATIN1编码表示,那coder的值就是0,否则就是UTF16编码,coder的值就是1。如果池中有,则不会放入,返回已有的池中的对象的地址。

Blue92120的博客 514

Java基础篇——Java String 深度解析:底层实现、不可变性、常量池与相关类全解读

java string详解

m0_59624833的博客 1654

[解密JVM-12] 字符串常量池

什么是字符串常量池?字符串的特点有哪些?

学哥斌的博客 415

Java String 字符串终极详解(全特性+全API+全示例)

Java String 字符串终极详解(全特性+全API+全示例)

qq_59093178的博客 1103

Java中基于字符串的理解

其他: trim() (去除首尾空白字符,不包含Unicode空白)、 strip() (JDK11+,去除所有Unicode空白)、 substring(beginIndex, endIndex) (JDK7+直接截取字符数组,JDK6会复制原数组,效率低)。- 分割: split(String regex) (正则分割,空字符串可能产生空数组,如 "a,,b".split(",") 结果为 ["a","","b"] )。- 构造方法: String s = new String("abc");

Ccuno的博客 298

Java基础面试

String以及StringTable复盘 String有两种实例化的方式: String s1 = “atguigu”; //字面量的定义方式 String s2 = new String(“hello”); jdk8和jdk9中String底层变化 jdk8中String底层是用final修饰的char数组。 jdk9中是用final修饰byte数组。 为什么要做出这样的修改呢? 因为大部分字符串都是拉丁字符,而拉丁字符只需要一个字节就可以了,而中文需要两个字节。以前统一用char就会浪费内存

qq_40875146的博客 200

Java 字符串专项知识点总结

◦ 常用方法:equals()(内容比较)、length()、charAt()、substring()、indexOf()、replace()、split()、trim()、valueOf()(基本类型转字符串)。new String("abc")会创建两个对象(常量池1个 + 堆内存1个)。◦ 常用方法:append()、insert()、delete()、reverse(),修改操作直接作用于原对象。◦ 通过intern()方法:手动将堆中的字符串对象加入常量池,若常量池已存在,则返回池中的对象地址。

asatongqq的博客 410

字符串的运用

equalsIgnoreCase(String another) 忽略大小写比较内容 如 "Abc".equals("abc") → true。- 一旦创建,字符序列不可修改,所有修改操作(如 substring 、 replace )都会返回新的 String 对象。- 手动入池: String s3 = new String("abc").intern();→ 返回常量池中的对象。4. 分割字符串时,正则表达式特殊字符(如 . 、 | )需转义(如 split("\\.") )。

Tonggggg_g的博客 771

5、JVM-字符串常量池StringTable分析

文章目录1.String的基本特性1.2 底层结构1.3 内存分配1.4 字符串拼接操作1.5 intern() 1.String的基本特性 String:字符串,使用一对""引起来表示 String声明为final的, 不可被继承 String实现了Serializable接口:表示字符串是支持序列化的。 实现了Comparable接口:表示String可以比较大小 要点: String在jdk8及以前内部定义了final char[] value用于存储字符串数据。jdk9时改为b

weixin_38650898的博客 393

八、JVM从入门到精通之String Table(字符串常量池)分析

前言:我们学习String Table之前,就无法避免的要先去学习下String,只有对String知己知彼了,才能更好的掌握和理解String Table。

猿小许的博客 393

【Java从入门到精通】第14篇:字符串的不可变性——String、StringBuilder、StringBuffer与字符串池的物理模型

String是Java中最常用的类,其不可变性设计深刻影响着程序的正确性与性能。本文从String内部final char[](JDK 9后改为byte[])的存储结构出发,论证不可变性如何保障字符串常量池的共享安全、HashSet中字符串键的哈希稳定性,以及多线程环境下字符串操作的免锁特性。深入字符串常量池的驻留机制与intern()方法的本地实现,对比StringBuilder与StringBuffer在单线程与多线程下的性能差异,并揭示JDK 9 Compact Strings优化如何通过byte[

2301_80672009的博客 205
上一篇: HotSpot虚拟机中的intrinsic是指什么?
下一篇: 即时编译器对于字段读取及存储指令的优化是什么?
Shockang
Shockang 优质创作者: 大数据技术领域 优质创作者: 大数据技术领域
博客等级 码龄11年 1万+粉丝 660原创
评论 30
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值