JVM进阶-面试字符串拼接底层(字符串常量池)

前言

我们大家都知道JVM中有一个常量池的概念,他的出现是为了省略我们一些基本变量重复创建导致空间浪费,我们在创建变量时变量将存入常量池中在下次创建我们就会直接引用字符串常量池中的对象。

但常量池究竟是如何运作的我们接下来看看吧

首先在阅读这篇文章的时候需要对JVM内存模型有一定的了解

示例

java 复制代码
String a = "aa";
String b = "a"+"a";
String c = "a";
String d = "a"+c;


sout(a == b); // true
sout(a == d); // false

====================================================

String a = new StringBuilder("aa").toString();
String b = "aa";
sout(a == b); //false

==================================================

String a = new StringBuild("aa").append("bb").toString();
String b = "aabb";
sout(a == b); //true

字符串常量池

在我们使用String b = "XXX"或者是aa("XX")这种直接引号形式静态声明字符串,都会向常量池中添加数据

1.6及以前有着永久代的概念(存储字符串常量池、对象class、静态变量)

JDK1.6后字符串常量池就到了栈内存中、永久代被元空间替代了

字符串常量池其实很像HashTable,key中存储对象指针,value中存储对象在堆空间中的内存地址,在我们程序中对象引用的就是我们的字符串常量池中的对象指针。!!!在每一次创建这种静态声明形式会先在常量池中遍历一遍找到了与他相同的对象就直接引用、没有找到就直接创建(这个创建又会遍历一次堆内存发现又相同的对象就直接引用到字符串常量池中,没有就自己创建)!!!

结合示例

java 复制代码
String a = "aa";
// 这一行在JVM编译的时候会对其进行优化变为:String b = "aa"
String b = "a"+"a";

在第一行执行的时候JVM中的字符串常量池还没有这个aa值的对象,那么在第一行会在堆内存中创建一个aa的字符串对象并将他记录到字符串常量池中

第二行执行的时候JVM先遍历字符串常量池,发现找到了那么就直接指向字符串常量池

我们可以发现他们引用的都是一个对象所以a、b等值

Stirng a = "a"
String b = "a" + a;

这一种形式JVM没有办法在编译的时候优化
在执行b的时候JVM会底层调用创建一个StringBuile然后将两个字符串都append进去然后再toString所以a、b不等值
java 复制代码
String a = new StringBuilder("aa").toString();
String b = "aa";
sout(a == b); //false

在这个理解起来会复杂一点,但是也非常简单

第一行:
    1.首先发现我们有一个字符串静态声明,这里会记入字符串常量池中
    2.new StringBuilder()会创建一个aa的StringBuilder对象
    3.使用StringBuild.toString()在底层会使用new String()所以这里又创建了一个变量
    
第二行:这里直接拿到我们字符串常量池中的数据

到这里我们就很好理解了a为toString后的值,b为字符串常量池中的值,所以a、b不等值
java 复制代码
String a = new StringBuild("aa").append("bb").toString();
String b = "aabb";
sout(a == b); //true

这个就然大家来判断一下吧
主要就是,在创建添加字符串常量池中会寻找堆中有没有相同的对象如果有就直接引用

后言

其他的基本类型的常量池就很简单了

Boolean在程序中就定义好了

Integer 在创建的时候就存储-128~127的值

intern

比如StringA.intern()

这个方法就是从字符串常量池中获取与这个String值相同的key如果找到了就返回字符串常量池的引用,如果没有找到就会创建(创建流程与上文讲述相似)

相关推荐
百锦再6 分钟前
第15章 并发编程
android·java·开发语言·python·rust·django·go
Chan1635 分钟前
【 Java八股文面试 | Redis篇 缓存问题、持久化、分布式锁 】
java·数据库·redis·后端·spring·缓存·面试
q***471842 分钟前
Spring Boot 整合 Druid 并开启监控
java·spring boot·后端
Propeller1 小时前
【Android】模板化解决复杂场景的滑动冲突问题
android·java
渡我白衣1 小时前
深入 Linux 内核启动:从按下电源到用户登录的全景解剖
java·linux·运维·服务器·开发语言·c++·人工智能
七夜zippoe1 小时前
Java 9+模块化系统(JPMS)详解:设计与迁移实践
java·开发语言·maven·模块化·jmm
techzhi1 小时前
Intellij idea 注释模版
java·python·intellij-idea
bagadesu1 小时前
MySQL----case的用法
java·后端
what_20181 小时前
idea启动项目配置环境变量(nacos 命名空间)
java·开发语言
Slow菜鸟1 小时前
Java 开发环境安装指南(三) | Maven 安装
java