【Java SE】Java中String的内存原理
参考笔记:
Java String 类深度解析:内存模型、常量池与核心机制_java stringx、-CSDN博客
解析java中String的内存原理_string s1 = new string("ab");内存分析-CSDN博客
目录
1.String初识
2.字符串字面量
3.内存原理图
4. 示例验证
4.1 字面量直接赋值
4.2 new方式赋值
4.3 new和直接赋值混合
4.4 字符串拼接
4.4.1 +号两边至少有一个变量
4.4.2 +号两边都是字面量
4.5 intern()方法
4.5.1 示例代码1
4.5.2 示例代码2
1.String初识
(1)Java 的 String 是引用数据类型
(2)因为字符串使用比较频繁,所以 Java 专门为字符串准备了一个字符串常量池。 Java 8 之前字符串常量池在方法区中,Java 8 之后在堆中,本文讲的是 Java 8 之前
(3)放在字符串常量池中的好处就是省去了对象的创建过程,从而提高程序的执行效率。常量池是一种缓存技术,缓存技术是提高程序执行效率的重要手段
(4)字符串一旦创建是不可变的(String 源码有一个属性:private final byte[] value)
示例:String s = "hello"
其中 "hello" 存储在字符串常量池中,字符串常量池中的 "hello" 不可变,不能变成 "hello123"。而 s 仍然可以指向其他的字符串对象,例如 s = "xyz"
2.字符串字面量
字符串字面量:我们自己给出的字符串,也可以称作字符串常量。如 "123","abc"
判断方法:简单来说就是在程序中的任何位置,只要出现带上英文双引号的就可以算是字符串字面量
字符串常量池规则
字符串字面量一旦出现,会先去方法区里的字符串常量池找有没有该字符串常量。
(1)如果有,则直接返回字符串常量池中存放该字符串的空间的地址
(2)如果没有,则在字符串常量池里面开辟一块空间用来存放该字符串常量,并返回空间地址
示例代码
public class demo {public static void main(String[] args) {String s1 = "123";String s2 = new String("456");//"456"String s3 = "12";String s4 = "k";String s5 = s3+s4;//"12K"String s6 = s3+"马";//"12马"String s7 = "s"+"abc";//"sabc"}
}
经过上述代码,字符串常量池中有字符串:"123","456","12","k","马","s","abc","sabc"
这些都是字符串字面量,但是字符串常量池中不会有 "12k" 、"12马"(后面会作解释)
3.内存原理图

4. 示例验证
4.1 字面量直接赋值
注:s1 == s2 比较的是 s1 与 s2 的引用地址是否相同, s1.eauals(s2) 比较的是 s1与 s2 的内容是否相同
示例代码
public class demo {public static void main(String[] args){String s1="12";//字符串字面量12会先在方法区中的字符串常量池中找,//发现没有同内容的字符串常量,那么就开辟一个新的空间,存放12//然后再把这个地址赋值给s1String s2="12";//字符串字面量12会现在方法区中的字符串常量池中找,//发现已经存在了字符串常量12了,此时无需再区开辟空间//只需要把已经存在的字符串常量的地址赋值给s2就行了//s1与s2指向的是同一个字符串常量的地址,所以s1==s2,输出trueSystem.out.println(s1==s2);}
}
示例代码内存原理图

4.2 new方式赋值
注:Java 开发中很少使用 new 的方式给 String 赋值,因为在堆中会产生不必要的内存分配,直接使用字面量赋值更高效
示例代码
public class demo {public static void main(String[] args) {String s1 = new String("123");String s2 = new String("123");//只要有new就会在堆内存中开辟空间//字符串字面量在字符串常量池中开辟的空间的那个地址值会存放到开辟的堆内存中//s1,s2指向的都是自己堆内存中开辟的空间,并没有直接指向字符串常量池的"123"的那个地址//因此s1与s2进行 == 比较,输出为falseSystem.out.println(s1 == s2);//s1与s2内容相同,输出为trueSystem.out.println(s1.equals(s2));}
}
示例代码内存原理图

4.3 new和直接赋值混合
示例代码
public class demo {public static void main(String[] args) {String s1=new String("123");String s2="12"+"3";//会在字符串常量池开辟"123","12","3"的空间,//"123"在字符串常量池中开辟的空间地址赋值到了s1中开辟的堆空间中,s1指向的是堆空间地址//"123"在字符串常量池中开辟的空间地址直接赋值给了s2//因此,s1与s2进行 == 比较,输出为falseSystem.out.println(s1==s2);}
}
示例代码内存原理图

4.4 字符串拼接
4.4.1 +号两边至少有一个变量
如果 + 号两边至少有一个是变量,则用 + 拼接生成的新的字符串不会被放到字符串常量池中,只会存放到堆中
示例代码
public class demo {public static void main(String[] args) {//字符串常量池中创建"123","456"String s1 = "123";String s2 = "456";//s3="123456"是拼接而来,所以"123456"不在字符串常量池中,存放在堆中String s3 = s1 + s2;//字符串常量池中创建"123456"//s4的引用是字符串常量池中存放"123456"的地址String s4 = "123456";//s3与s4的引用不同,所以输出为falseSystem.out.println(s3 == s4);//s3与s4的内容相同,输出为trueSystem.out.println(s3.equals(s4));}
}
4.4.2 +号两边都是字面量
如果 + 号两边都是字符串字面量(常量),编译器会进行自动优化。在编译阶段进行拼接。 + 号两边的字符串字面量、拼接后的新字符串都会被放到字符串常量池中,返回的引用也是来自字符串常量池
示例代码
public class demo {public static void main(String[] args) {//字符串常量池中创建"123"、"456"、"123456"//返回字符串常量池中存放"123456"的地址String s1 = "123"+"456";//字符串常量池中已存在"456"//返回字符串常量池中存放"456"的地址String s2 = "456";//s2与"456"的引用相同,所以输出为trueSystem.out.println(s2 == "456");//字符串常量池中已存在"123456"//返回字符串常量池中存放"123456"的地址String s3 = "123456";//s1与s3的引用相同,所以输出为trueSystem.out.println(s1 == s3);}
}
示例代码内存原理图

4.5 intern()方法
intern() 检查当前该字符串字面量是否已经存放于字符串常量池中
(1)存在:直接返回字符串常量池中存放该字符串字面量的空间地址
(2)不存在:将新的字符串字面量添加到常量池中,并返回引用
4.5.1 示例代码1
示例代码
public class demo {public static void main(String[] args) {String s1 = new String("123");//在字符串常量池开辟"123"的空间//"123"在字符串常量池中开辟的空间地址赋值到了s1中开辟的堆空间中,s1指向的是堆空间地址//字符串常量池中已有"123",调用intern()返回其在字符串常量池中的引用地址String s2 = new String("123").intern();//字符串常量池中已有"123",返回其在字符串常量池中的引用地址String s3 = "123";System.out.println(s1==s2);//falseSystem.out.println(s2==s3);//trueSystem.out.println(s1==s3);//false}
}
示例代码内存原理图

4.5.2 示例代码2
在 4.4.1 提到,如果 + 号两边至少有一个是变量,则用 + 拼接生成的新字符串不会被放到字符串常量池中,只会存放到堆中
这种场景下就可以用 intern() 方法来将 + 拼接生成的新字符串手动添加到字符串常量池中,并且返回的引用就来自字符串常量池
示例代码
public class demo {public static void main(String[] args) {String s1 = "hello";String s2 = "world";//拼接生成的"helloworld",存放在堆中String s3 = s1 + s2;//手动将拼接生成的"helloworld"添加到字符串常量池中,并返回引用String s4 = s3.intern();//字符串常量池中已有"helloworld",返回其在字符串常量池中的引用地址String s5 = "helloworld";//输出trueSystem.out.println(s4==s5);}
}相关文章:
【Java SE】Java中String的内存原理
参考笔记: Java String 类深度解析:内存模型、常量池与核心机制_java stringx、-CSDN博客 解析java中String的内存原理_string s1 new string("ab");内存分析-CSDN博客 目录 1.String初识 2.字符串字面量 3.内存原理图 4. 示例验证 4.…...
IDEA提示将方法形参更改为(什么什么类型),要检查对应的实体类中的字段类型是否正确
IDEA提示inviteCodeId应该是字符串,明显不对,后来检查发现是FakeRegistration类中把inviteCodeId定义为String类型了。...
DeepSeek-OpenSourceWeek-第五天-Launch of 3FS and Smallpond Framework
2025 年 2 月 28 日,DeepSeek 在开源周的最后一天宣布推出了 Fire-Flyer File System(3FS)和 Smallpond 数据处理框架。这些创新旨在提升数据访问和处理能力,特别是针对 AI 训练和推理工作负载。 Fire-Flyer File System (3FS) 3FS 是一种高性能的分布式文件系统,专为应对…...
【芯片设计】NPU芯片前端设计工程师面试记录·20250227
应聘公司 某NPU/CPU方向芯片设计公司。 小声吐槽两句,前面我问了hr需不需要带简历,hr不用公司给打好了,然后我就没带空手去的。结果hr小姐姐去开会了,手机静音( Ĭ ^ Ĭ )面试官、我、另外的hr小姐姐都联系不上,结果就变成了两个面试官和我一共三个人在会议室里一人拿出…...
初阶数据结构(C语言实现)——3顺序表和链表(3)
3.链表 3.1 链表的概念及结构 概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 链表的物理结构 1.从上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续…...
Kubernetes故障排查实战指南
前言 在云原生时代,Kubernetes已成为容器编排的事实标准。然而,随着系统规模和复杂度的增加,故障排查变得越来越具有挑战性。本文将从实战角度,系统化介绍K8s故障排查方法和最佳实践。 © ivwdcwso (ID: u012172506) 一、故障排查方法论 1.1 三步排查法 问题定位:快…...
使用 VSCode 代替 BeyondStudio for NXP 开发 JN 5169
使用 VSCode 代替 BeyondStudio for NXP 开发 JN 5169 一、安装 VSCode二、搭建 NXP JN5169 ZigBee 3.0 开发环境和下载示例工程三、配置 VSCode1、配置环境变量 MYSYS_HOME2、VSCode 安装以下插件3、VSCode 配置头文件路径 四、编译工程1、JN-AN-1219 有 6 个构建选项2、修改 …...
Python常见面试题的详解24
1. 如何对关键词触发模块进行测试 要点 功能测试:验证正常关键词触发、边界情况及大小写敏感性,确保模块按预期响应不同输入。 性能测试:关注响应时间和并发处理能力,保证模块在不同负载下的性能表现。 兼容性测试:测…...
加载大数据时性能压力优化
1. 减少数据请求量 分页加载(Pagination) 原理:将数据拆分为多页,按需加载。实现: 传统分页(页码切换)。无限滚动(滚动到底部自动加载下一页,如社交媒体)。…...
动态自定义标签属性页面(Tomcat 9)
java文件 ,包名org.rain.tag package org.rain.tag; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.DynamicAttributes; import javax.servlet.jsp.…...
使用Fuse-DFS挂载文件存储 HDFS-后端存储ceph
1. 编译环境准备 yum install cmake3 ln -s /usr/bin/cmake3 /usr/bin/cmake yum install gcc-c安装挂载依赖 yum -y install fuse fuse-devel fuse-libs执行以下命令,载入FUSE模块 modprobe fuse2. 下载源码包 hadoop-3.3.4-src.tar.gz解压后执行以下命令 打开…...
DBGPT安装部署使用
简介 DB-GPT是一个开源的AI原生数据应用开发框架(AI Native Data App Development framework with AWEL(Agentic Workflow Expression Language) and Agents)。 目的是构建大模型领域的基础设施,通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Mul…...
How to use VRX on ubuntu20.04 with ROS1 Noetic?[2]
How to use VRX on ubuntu20.04 with ROS1 Noetic?[2] 1.Which topics2.Control1.1操作模拟船(1)命令行直接发布(2)启动键盘控制文件 3.Customer your VRX world3.1Which world parameters3.2改变风的参数 3.2.1更改默认参数&…...
yolov8 目标追踪 (源码 +效果图)
1.在代码中 增加了s键开始追踪 e键结束追踪 显示移动距离(代码中可调标尺和像素的比值 以便接近实际距离) 2.绘制了监测区域 只在区域内的检测 3.规定了检测的类别 只有人类才绘制轨迹 import osimport cv2 from ultralytics import YOLO from collections import defaultdic…...
运维Apache面试题及参考答案
目录 简述 Apache Web 服务器的主要特点及适用场景 Apache 的默认监听端口是什么?如何修改为其他端口? Apache 的主配置文件名称及路径是什么?不同 Linux 发行版的默认路径有何差异? 解释 Apache 的 MPM(Multi-Processing Module)机制,列举常见的工作模式(如 prefor…...
基于Python的web漏洞挖掘,漏洞扫描系统(附源码,部署)
本次技术通过利用Python技术来开发一款针对web漏洞挖掘扫描的技术,通过web漏洞的挖掘扫描来实现对网站URL的漏洞检测,通过高中低风险的判断来实现对一款网站中存在的漏洞进行可视化的分析,从而能够找到问题并且尽快的实现问题的解决。 博主介…...
K8s部署主从结构MySQL服务
01 介绍 RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字、启停顺序等都是随机分配的,而StatefulSet,管理所有有状态的服务。 StatefulSet为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,一定的启停顺序,在StatefulSet中,Pod名字…...
岳阳市美术馆预约平台(小程序论文源码调试讲解)
第4章 系统设计 一个成功设计的系统在内容上必定是丰富的,在系统外观或系统功能上必定是对用户友好的。所以为了提升系统的价值,吸引更多的访问者访问系统,以及让来访用户可以花费更多时间停留在系统上,则表明该系统设计得比较专…...
ubuntu22.04系统如何自建2级ntp服务器
一:ntp服务器详情 服务器型号 系统版本 IP地址 主机名 ntp服务版本 虚拟机8c-32g-1T Ubuntu22.04 10.20.30.2 DMZ-NTP-SERVER 4.2.8p15 二:ntp服务端部署配置脚本 #!/bin/bash # 脚本信息 echo "--------------------------…...
DeepSeek赋能智慧社区:提升社区治理,优化资源配置,带来全新变革
在数字化浪潮的推动下,智慧社区正逐渐成为城市发展的重要方向。作为一款先进的人工智能大模型,DeepSeek凭借其强大的多模态数据分析和智能决策能力,正在为智慧社区的建设注入新的活力。 标准规范及顶层设计指南、供应商整体解决方案合集、供应…...
spring注解开发(Spring整合MyBatis——Mapper代理开发模式、(Spring、MyBatis、Jdbc)配置类)(6)
目录 一、纯MyBatis独立开发程序。 (1)数据库与数据表。 (2)实体类。 (3)dao层接口。(Mapper代理模式、无SQL映射文件——注解配置映射关系) (4)MyBatis核心配…...
springcloud组件调用顺序
Spring Cloud 组件的调用顺序并不是固定不变的,它依赖于具体的业务场景和微服务架构的设计。然而,可以概括出一个典型的微服务架构中 Spring Cloud 组件的调用流程,这个流程大致可以分为以下几个步骤: 服务注册与发现:…...
【MySQL】数据库-图书管理系统(CC++实现)
一.预期功能 该图书管理系统设计提供基本的设计模版,涉及数据库的增删查改等操作,包含登录功能,图书管理功能,图书借阅功能,用户管理功能等基础功能,详细功能查看以下菜单表,共包含三个菜单&am…...
VSCode轻松调试运行C#控制台程序
1.背景 我一直都是用VS来开发C#项目的,用的比较顺手,也习惯了。看其他技术文章有介绍VS Code更轻量,更方便。所以我专门花时间来使用VS Code,看看它是如何调试代码、如何运行C#控制台。这篇文章是一个记录的过程。 2.操作 2.1 V…...
python-leetcode-下一个排列
31. 下一个排列 - 力扣(LeetCode) class Solution:def nextPermutation(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""# Step 1: Find the first decreasing element …...
c++中初始化列表的使用
在 C 中,初始化列表是在构造函数的定义中,用于对类的成员变量进行初始化的一种方式。它紧跟在构造函数的参数列表之后,使用冒号 : 分隔,各成员变量的初始化用逗号 , 分隔。下面详细介绍初始化列表及其参数的含义。 基本语法 clas…...
2025年2月28日(RAG)
从图片中的内容来看,用户提到的“RAG”实际上是“Retrieval-Augmented Generation”的缩写,中文称为“检索增强生成”。这是一种结合了检索(Retrieval)和生成(Generation)的技术,用于增强自然语…...
学睿德毅AI 赋能教育拓展短视频创作边界
在数字技术飞速发展的当下,短视频行业已成为推动社会经济发展的重要力量。学睿德毅紧跟时代步伐,聚焦 AI 技术在教育领域的创新应用,精心打造了一套专业且系统的短视频剪辑课程体系。该体系以 “技术与创意并重,理论共实践一色” …...
Jsmoke-一款强大的js检测工具,浏览器部署即用,使用方便且高效
目录标题 Jsmoke 🚬🚬 by Yn8rt使用方式界面预览功能特性支持的敏感信息类型 Jsmoke 🚬🚬 by Yn8rt 该插件由 Yn8rt师傅 开发,插件可以理解为主动版的hae和apifinder,因为其中的大多数规则我都引用了&a…...
iphone上ios设备开启safari开发者debug模式,配合mac电脑使用
1.mac操作 mac的safari上打开开发者模式,打开显示网页开发者功能 2.开启IPhone的Safari调试模式 启用 Web 检查 功能,打开 iPhone 依次进入 设置 > Safari浏览器 > 高级 > 网页检查器 > 启用。 3.调试步骤 先用IPhone 的Safari打开要调试…...
