【Java SE】Java中String的内存原理

news2025/5/17 4:57:56

参考笔记:

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);

    }
}

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

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

相关文章

IDEA提示将方法形参更改为(什么什么类型),要检查对应的实体类中的字段类型是否正确

IDEA提示inviteCodeId应该是字符串,明显不对,后来检查发现是FakeRegistration类中把inviteCodeId定义为String类型了。

【芯片设计】NPU芯片前端设计工程师面试记录·20250227

应聘公司 某NPU/CPU方向芯片设计公司。 小声吐槽两句,前面我问了hr需不需要带简历,hr不用公司给打好了,然后我就没带空手去的。结果hr小姐姐去开会了,手机静音( Ĭ ^ Ĭ )面试官、我、另外的hr小姐姐都联系不上,结果就变成了两个面试官和我一共三个人在会议室里一人拿出…

初阶数据结构(C语言实现)——3顺序表和链表(3)

3.链表 3.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、修改 …

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…

基于Python的web漏洞挖掘,漏洞扫描系统(附源码,部署)

本次技术通过利用Python技术来开发一款针对web漏洞挖掘扫描的技术,通过web漏洞的挖掘扫描来实现对网站URL的漏洞检测,通过高中低风险的判断来实现对一款网站中存在的漏洞进行可视化的分析,从而能够找到问题并且尽快的实现问题的解决。 博主介…

岳阳市美术馆预约平台(小程序论文源码调试讲解)

第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核心配…

【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 …

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打开要调试…

Datawhale 数学建模导论二 笔记5 多模数据与智能模型

主要涉及到的知识点有: 数字图像处理与计算机视觉 计算语言学与自然语言处理 数字信号处理与智能感知 10.1 数字图像处理与计算机视觉 视觉信息是我们第一种非常规的数据模式,在Python当中可以使用opencv处理数字图像,并提取出视觉特征用…

如何在一台服务器上搭建 mongodb副本集1主2从节点

在一台服务器上搭建 MongoDB 副本集(1 主节点 2 从节点)可以通过运行多个 MongoDB 实例并使用不同端口和数据目录来实现。以下是详细步骤: 1. 准备工作 确保已安装 MongoDB。为每个实例创建独立的数据目录和日志文件。 2. 创建数据目录和…

TikTok隐私保护措施:确保用户安全

TikTok隐私保护措施:确保用户安全 在这个信息爆炸的时代,社交媒体平台的隐私保护问题日益成为公众关注的焦点。TikTok,作为全球领先的短视频平台,拥有庞大的用户群体,因此,其隐私保护措施显得尤为重要。本…