Java中字符串的初始化详解
前言
在深入学习字符串类之前,我们先搞懂JVM是怎样处理新生字符串的。当你知道字符串的初始化细节后,再去写String s = "hello"或String s = new String("hello")等代码时,就能做到心中有数。
首先得搞懂字符串常量池的概念,下面进入正文吧。
常量池
把经常用到的数据存放在某块内存中,避免频繁的数据创建与销毁,实现数据共享,提高系统性能。
八种基础数据类型除了float和double都实现了常量池技术。在近代的JDK版本中(1.7后),字符串常量池被实现在Java堆内存中。
下面通过三行代码让大家对字符串常量池建立初步认识:
public static void main(String[] args) {String s1 = "hello";String s2 = new String("hello");System.out.println(s1 == s2); //false
}
先来看看第一行代码String s1 = "hello";

直接通过双引号( String s1 = “hello”)声明字符串的方式,虚拟机首先会到字符串常量池中查找该字符串是否已经存在。如果存在会直接返回该引用,如果不存在则会在堆内存中创建该字符串对象,然后到字符串常量池中注册该字符串。
上面的代码中( String s1 = “hello”)虚拟机首先会到字符串常量池中查找是否有存在hello字符串对应的引用。发现没有后会在堆内存创建hello字符串对象(内存地址0x0001),然后到字符串常量池中注册地址为0x0001的hello对象,也就是添加指向0x0001的引用。最后把字符串对象返回给s1。
下面看String s2 = new String("hello");

当我们使用new关键字创建字符串对象的时候,JVM将不会查询字符串常量池,它将会直接在堆内存中创建一个字符串对象,并返回给所属变量。
所以s1和s2指向的是两个完全不同的对象,判断s1 == s2的时候会返回false。
再来看下面的示例:
public static void main(String[] args) {String s1 = new String("hello ") + new String("world");s1.intern();String s2 = "hello world";System.out.println(s1 == s2); //true
}
第一行代码String s1 = new String("hello ") + new String("world");的执行过程是这样子的:
-
依次在堆内存中创建
hello和world两个字符串对象; -
然后把它们拼接起来 (底层使用StringBuilder实现);
-
在拼接完成后会产生新的
hello world对象,这时变量s1指向新对象hello world。
执行完第一行代码后,内存是这样子的:

第二行代码s1.intern();
当调用intern()方法时,首先会去常量池中查找是否有该字符串对应的引用,如果有就直接返回该字符串;
如果没有,就会在常量池中注册该字符串的引用,然后返回该字符串。
由于第一行代码采用的是new的方式创建字符串,所以在字符串常量池中没有保存hello world对应的引用,虚拟机会在常量池中进行注册,注册完后的内存示意图如下:

第三行代码String s2 = "hello world";
首先虚拟机会去检查字符串常量池,发现有指向hello world的引用。然后把该引用所指向的字符串直接返回给所属变量。
执行完第三行代码后,内存示意图如下:

如图所示,s1和s2指向的是相同的对象,所以当判断s1 == s2时返回true。
总结:
-
当用new关键字创建字符串对象时,不会查询字符串常量池;
-
当用双引号直接声明字符串对象时,虚拟机将会查询字符串常量池。
说白了就是:字符串常量池提供了字符串的复用功能,除非我们要显式创建新的字符串对象,否则对同一个字符串虚拟机只会维护一份拷贝。
反编译代码
下面我们再来看一个示例:
public class Main {public static void main(String[] args) {String s1 = "hello ";String s2 = "world";String s3 = s1 + s2;String s4 = "hello world";System.out.println(s3 == s4);}
}
首先第一行和第二行是常规的字符串对象声明,它们分别会在堆内存创建字符串对象,并会在字符串常量池中进行注册。
影响我们做出判断的是第三行代码String s3 = s1 + s2;,我们不知道s1 + s2在创建完新字符串hello world后是否会在字符串常量池进行注册。
简单点说:我们不知道这行代码是以双引号形式声明字符串,还是用new关键字创建字符串。
那么我们看下这端代码的反编译后的代码:
PS D:\code\javaSE\target\classes\demo> javap -c .\Main.class
Compiled from "Main.java"
public class demo.Main {public demo.Main();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: ldc #2 // String hello2: astore_13: ldc #3 // String world5: astore_26: new #4 // class java/lang/StringBuilder9: dup10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V13: aload_114: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;17: aload_218: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;24: astore_325: ldc #8 // String hello world27: astore 429: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;32: aload_333: aload 435: if_acmpne 4238: iconst_139: goto 4342: iconst_043: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V46: return
}
直接看重点:
-
21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; -
24: astore_3 -
虚拟机调用StringBuilder的
toString()方法获得字符串hello world,并存放至s3。 -
下面是我们追踪StringBuilder的
toString()方法源码:@Override public String toString() {// Create a copy, don't share the arrayreturn new String(value, 0, count); }
通过以上源码可以看出:s3是通过new关键字获得字符串对象的。
回到题目,也就是说字符串常量表中没有存储hello world的引用,当s4以引号的形式声明字符串时,由于在字符串常量池中查不到相应的引用,所以会在堆内存中新创建一个字符串对象。 所以s3和s4指向的不是同一个字符串对象, 结果为false。
相关文章:
Java中字符串的初始化详解
前言 在深入学习字符串类之前,我们先搞懂JVM是怎样处理新生字符串的。当你知道字符串的初始化细节后,再去写String s "hello"或String s new String("hello")等代码时,就能做到心中有数。 首先得搞懂字符串常量池的概…...
面向对象(七)-- 代码块
目录 1. 代码块的概述 2. 代码块的分类 3. 代码块的执行优先级 1. 代码块的概述 在Java中,使用 { } 括起来的代码被称为代码块 2. 代码块的分...
《编程思维与实践》1037.一元多项式乘法
《编程思维与实践》1037.一元多项式乘法 题目 思路 比较容易想到将步骤分为三步: 1.读取多项式每项的系数(coefficient)和对应的指数(dim); 2.进行多项式乘法; 3.输出进行多项式乘法后的非零项系数. 其中多项式乘法可以通过循环来处理,输出可以用if来判断系数是否为0,需要考虑…...
top命令学习
文章目录 一、top命令回显信息含义1、第一行2、第二行3、第三行4、第四行5、第五行6、第六行进程信息 二、top简单交互1、按数字“1”,显示列出所有cpu的信息2、按“M”,按内存使用率从大到小排序3、按“P”,按CPU使用率从大到小排序 一、top…...
PHP数组的功能及实现案例
目录 前言 一、什么是数组 二、创建关联数组 1.1运行流程(思想) 1.2代码段 1.3运行截图 三、创建索引数组 1.1运行流程(思想) 1.2代码段 1.3运行截图 前言 1.若有选择,可实现在目录里进行快速查找ÿ…...
Cesium实践(4)——空间数据加载
文章目录 前言几何形体点线面体 标签文字图标 几何文件GeoJsonKMLCZML 三维模型总结 前言 本文介绍Cesium如何加载空间数据,空间数据即明确定义在三维空间中的数据,空间数据包括以下几类:1、几何形体(点、线、面、体)…...
FreeRTOS(三)——应用开发(一)
文章目录 0x01 FreeRTOS文件夹FreeRTOSConfig.h文件内容上面定义的宏决定FreeRTOS.h文件中的定义0x02 创建任务创建静态任务过程configSUPPORT_STATIC_ALLOCATION创建动态任务过程configSUPPORT_DYNAMIC_ALLOCATION 0x03 FreeRTOS启动流程启动流程概述 0x04 任务管理任务调度器…...
这些 Linux 的自动化技巧,教你轻松完成任务
linux 系统的 web 网站在运营状态时,我们常需要对网站进行维护,例如查看资源剩余并做出响应、日志分割、数据整理,在特定状态执行特定任务等等,这些都会需要 linux能实现自动执行某些任任务。本篇博文介绍如何进行常见的linux自动…...
PAL制搜台
PAL电视制式 PAL电视制式(Phase Alternating Line)采用625线制式,视讯制式采用PAL-B/G、PAL-D/K、PAL-I等。PAL电视不像NTSC制式有中心频点,它采用宽带的频率范围进行电视信号的调制和传输。 PAL电视制式频率 PAL电视采用UHF(超高频)和VHF(甚高频)两个频段进行电视信号的传输…...
SpringBoot 使用 Docker Registry Api
Spring Boot是一个快速开发Web应用程序的框架,它提供了许多方便的工具和库,使得开发过程更加高效。在部署Spring Boot应用程序时,使用Docker容器是现代化和流行的选择。在此背景下,本文将介绍如何使用Docker Registry API来构建、…...
Win10任务栏卡死怎么办?这3个方法快收藏!
案例:win10任务栏卡死 【姐妹们,我的win10任务栏一直卡着,我完全没法使用计算机了,遇到这种情况,我应该怎么做呢?求大家给我支支招!感谢感谢!】 我们使用电脑的过程中,…...
这一篇搞定Spring
文章目录 一、引言1.1 原生web开发中存在哪些问题? 二、Spring框架2.1 概念2.2 访问与下载 三、Spring架构组成四、山寨版的Spring容器4.1准备工作4.2 山寨IOC容器4.3 配置文件告诉容器 管理哪些bean4.4 相关类4.5 测试 容器 五、构建Maven项目5.1 新建项目5.2 选择…...
软测如果这么学,培训班都得倒闭,直接省去上万元的学费
俗话说外行看热闹,内行看门道。 写这篇文章,是希望把我的一些我认为是非常有价值的经验总结出来,能够帮助刚做测试不久的新同学,或者是测试经验丰富的老同学以共享。 希望我们可爱的新同学,准备要在测试领域耕耘的伙…...
赎金信(Hash的应用)
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以,返回 true ;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 来源:力扣࿰…...
4月更新!EasyOps®全平台27项新功能一口气来袭~
又到了每月产品盘点时刻,27大新功能上线和升级优化,设计Hyperlnsight超融合持续观测平台、DevOps持续交付平台、AutoOps自动化运维平台、ITSM服务平台、公共服务,在不断的技术创新过程中,进一步加速IT运维效率升级。 下面和小编一…...
程序计算任意连续的12个月公里数不超三万公里预警
为了比亚迪的电池终身质保,写了个简单算法,计算任意12个连续的月份公里数加起来不超过3万公里的预警import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; import java.util.stream.Collectors;/***…...
【IMU】IMU知多少之42866
ICM-42688-P数据手册中加速度计和角速度计的超量程阈值分别如下: 加速度计超量程阈值: 数字量(LSB):16g 模拟量(g):22g 角速度计超量程阈值: 数字量(LSB&a…...
谁说不能用中文写代码?
入门教程、案例源码、学习资料、读者群 请访问: python666.cn 大家好,欢迎来到 Crossin的编程教室 ! 现代计算机和编程的起源和推动力量主要源自美国,再加上26个字母很便于表示(算上大小写,6位bit就够了&am…...
Java阶段二Day07
Java阶段二Day07 文章目录 Java阶段二Day07V17UserControllerDispatcherServletControllerRequestMapping V18DispatcherServletHandleMapping V19BirdBootApplication 线程池线程的执行过程线程池API 数据库数据库的基本概念数据库管理系统中常见的概念 SQL分类DDL语言-数据定…...
React Native iOS打包详细步骤
一、在自己项目的iOS文件夹下新建一个文件夹取名bundle 二、将打包命令写到项目package.json文件里,终端执行 npm run bundle-ios 先添加如下(注意:这里写的路径"./ios/bundle"就是上面bundle创建的文件夹):…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
