【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)JavaString 是引用数据类型

(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 比较的是 s1s2 的引用地址是否相同, s1.eauals(s2) 比较的是 s1s2 的内容是否相同

示例代码 

public class demo {
    public static void main(String[] args){
        String s1="12";
        //字符串字面量12会先在方法区中的字符串常量池中找,
        //发现没有同内容的字符串常量,那么就开辟一个新的空间,存放12
        //然后再把这个地址赋值给s1

        String s2="12";
        //字符串字面量12会现在方法区中的字符串常量池中找,
        //发现已经存在了字符串常量12了,此时无需再区开辟空间
        //只需要把已经存在的字符串常量的地址赋值给s2就行了

        //s1与s2指向的是同一个字符串常量的地址,所以s1==s2,输出true
        System.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进行 == 比较,输出为false
        System.out.println(s1 == s2);
        
        //s1与s2内容相同,输出为true
        System.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进行 == 比较,输出为false
        System.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的引用不同,所以输出为false
        System.out.println(s3 == s4);
        //s3与s4的内容相同,输出为true
        System.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"的引用相同,所以输出为true
        System.out.println(s2 == "456");

        //字符串常量池中已存在"123456"
        //返回字符串常量池中存放"123456"的地址
        String s3 = "123456";

        //s1与s3的引用相同,所以输出为true
        System.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);//false
        System.out.println(s2==s3);//true
        System.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";

        //输出true
        System.out.println(s4==s5);

    }
}

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

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

相关文章

(0)阿里云大模型ACP-考试回忆

这两天通过了阿里云大模型ACP考试,由于之前在网上没有找到真题,导致第一次考试没有过,后面又重新学习了一遍文档才顺利通过考试,这两次考试内容感觉考试题目90%内容是覆盖的,后面准备分享一下每一章的考题,…

1.2.3 使用Spring Initializr方式构建Spring Boot项目

本实战概述介绍了如何使用Spring Initializr创建Spring Boot项目,并进行基本配置。首先,通过Spring Initializr生成项目骨架,然后创建控制器HelloController,定义处理GET请求的方法hello,返回HTML字符串。接着&#xf…

013作用域

一、基本概念 C语言中,标识符都有一定的可见范围,这些可见范围保证了标识符只能在一个有限的区域内使用,这个可见范围,被称为作用域(scope)。 软件开发中,尽量缩小标识符的作用域是一项基本原…

IP段转CIDR:原理Java实现

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…

使用PDFMiner.six解析PDF数据

PDF(可移植文档格式)文件是由Adobe创建的一种灵活的文件格式,它允许文档在不同的软件、硬件和操作系统中一致地显示。每个PDF文件都包含对固定布局文档的全面描述,包括文本、字体、图形和其他必要的显示元素。pdf通常用于文档共享…

DeepSeek后训练:监督微调和强化学习

注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】 文章目录 DeepSeek大模型技术系列十二DeepSeek大模型技术系列十二》DeepS…

蓝桥杯好题推荐----高精度乘法

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 题目链接 P1303 A*B Problem - 洛谷https://www.luogu.com.cn/problem/P1303 解题思路 这道题的思路,其实和前面差不多,我们主要说一下最为关键的部分&…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.3.2Kibana可视化初探

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 10分钟快速部署Kibana可视化平台1. Kibana与Elasticsearch关系解析1.1 架构关系示意图1.2 核心功能矩阵 2. 系统环境预检2.1 硬件资源配置2.2 软件依赖清单 3. Docker快速部…

low rank decomposition如何用于矩阵的分解

1. 什么是矩阵分解和低秩分解 矩阵分解是将一个矩阵表示为若干结构更简单或具有特定性质的矩阵的组合或乘积的过程。低秩分解(Low Rank Decomposition)是其中一种方法,旨在将原矩阵近似为两个或多个秩较低的矩阵的乘积,从而降低复…

算法题(81):询问学号

审题: 需要我们根据给出的n值确定录入数据个数,然后根据给出的数据存储学号。再根据m值确定需要输出的学号个数,然后根据数组内容输出学号 思路: 我们可以利用数组进行数据顺序存储,以及随机读取完成本题 由于学号最大为1e9&#…

项目开发时,涉及到的css样式

本文章,主要用来收集vue项目开发时,遇到的各种css样式问题。 1、如何让容器的高度等于浏览器窗口的高度? 问题描述:我们的微软浏览器和谷歌浏览器的窗口高度不一致,但是我们想无论打开哪个浏览器,都让我们项…

萌新学 Python 之 os 模块

os 模块:主要提供程序与操作系统进行交互的接口 先导入模块:import os 1. os.listdir(),获取当前目录的文件,返回到列表中 2. os.mkdir(文件目录, mode 0o777),创建目录,777 表示读写程序 在当前目录下…

Linux系统下Mplayer的高效人机操作界面设计

1. 项目背景 Mplayer作为经典开源媒体播放器,存在以下交互缺陷: 默认命令行界面需记忆复杂指令(如:mplayer -fs -playlist file.list) 缺乏可视化播放列表管理 状态信息展示不直观(需依赖终端输出&#…

某住宅小区地下车库安科瑞的新能源汽车充电桩的配电设计与应用方案

摘要: 文中以某住宅小区建设工程为例,重点研究了住宅小区地下车库新能源汽车充电桩配电设计,从位置设置、安装方式选择、配电箱设置、配电箱回路设置、供配电系统设计等方面展开分析,提出了民用建筑充电桩设计的科学建议,为新能源充电桩的推广应用提供参考。 关键…

达梦:内存相关参数

目录 28个相关参数1. 内存池相关MEMORY_POOLMEMORY_N_POOLSMEMORY_BAK_POOL 2. 大缓冲区相关HUGE_BUFFERHUGE_BUFFER_POOLS 3. 共享缓冲区相关BUFFERBUFFER_POOLSBUFFER_MODEMAX_BUFFER 4. 快速池相关FAST_POOL_PAGES 5. 回收池相关RECYCLE_POOLS 6. 回滚段池相关ROLLSEG_POOLS…

TCP的三次握手与四次挥手:建立与终止连接的关键步骤

引言 ‌TCP(传输控制协议)工作在OSI模型的传输层‌。OSI模型将计算机网络功能划分为七个层级,从底层到顶层依次是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。传输层负责在网络节点之间提供可靠的端到端通信&a…

游戏引擎学习第129天

仓库:https://gitee.com/mrxiao_com/2d_game_3 小妙招: vscode:定位错误行 一顿狂按F8 重构快捷键:F2 重构相关的变量 回顾并为今天的内容做准备 今天的工作主要集中在渲染器的改进上,渲染器现在运行得相当不错,得益于一些优化和组织上的改进。我们计…

【Swift 算法实战】城市天际线问题解法

网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…

「爬虫实战分享:如何高效爬取某汽车官方销售排行榜」

本文目录 💖前言一、💫代理IP的作用二、💫爬虫中的挑战1.代理IP的质量和稳定性2.IP封禁问题3. 反爬虫技术的升级 三、💫亮数据动态代理:数据采集的可靠伙伴1、真实体验 四、💫爬虫实战:使用亮数…

中央一号文件里的三维革命:数字孪生如何重构智慧乡村生态?

2024年中央一号文件提出"建设宜居宜业和美乡村",这一目标背后离不开数字技术的支撑。在浙江某数字乡村试点,凡拓数创通过三维建模还原整村风貌,路灯能耗、垃圾分类、古建保护等数据在虚拟空间中实时跳动。管理人员坦言:…