String常量池之存储过程


首先话不多吧!

1.		int num = 10;
    	num = 111;
    	System.out.println(num);//111

2.      	String str = "a";
    	System.out.println(str);//a
    	str = "b";
    	System.out.println(str);//b
3
		String str5 = new String("hello"); 
		String str6 = new String("hello");
		System.out.println("str5==str6:" + (str5 == str6));//false

以上代码:我相信有基础的人都会:注释后的是结果!

#1.基本数据类型的存储过程是:
在这里插入图片描述

2和3.使用引用来定义:
一个是直接赋值;一个是new 一个实例来存储。
他们直接的存储方式是如何的?
在这里插入图片描述

1.为什么常量字符串String是不可以变的?

通过源码查看:
我们可以发现:
在这里插入图片描述
1.String不可以变:是因为 String是final定义的因此不可改变;
但是:–>String是定义在类的前面:表示该类是不能被继承;不能被继承和该字符串不能改变是两码事(这个是错误的解释
2.private final char value【】字符数组;字符串其实就是字符数组:字符数组的本质就是字符串用来存储数据的数组
因为你存储字符前面有个final所以你的字符串是不能改变的(这个也是不对的

	**注意**:final是定义在变量之前;一个final定义在变量之前;(说明该变量是不能被改变的)(我们这个是变量是应用类型的变量);我们现在定义的这个数组是引用类型;有final修饰:说明我们这个引用不能改变;不是说我们这个值不能改变(这个是我的理解)

2. 最后,正确的解释:

1)这个是官方的解释:
在这里插入图片描述
2)这关系到:方法区中常量池、栈、堆之间的存储过程(个人理解)
方法区:->包括:常量池
字符串常量池的位置在方法区中;
常量池的作用:因为字符串用的很频繁,字符串不是基本数据类型 ;是对象类型;传统的定义声明:Xxx xx=new Xxx();产生一个新空间
如果下次再用就再一次new一个很麻烦,会造成内存的消耗过大;***String x=“a”; String xx=“b”***,所以就需要常量池;
a.***当你声明一个字符串的时候;一开始常量池是没有你声明的字符串的,声明后常量池会开辟一个空间存储声明的值 同一块存储空间中有(“a”、“b”)***;
1)就是使用字符串时,先在常量池寻找,如果有,则使用,如果没,则创建后 放入常量池并使用。

String str5 = new String("hello");
String str6 = new String("hello");
System.out.println("str5==str6:" + (str5 == str6));

2)如果是new 一个字符串;则会使再常量池中开辟新的空间;空间a 、存储(str5)、空间b、存储(str6)
3)以下图片可以更好的理解
在这里插入图片描述

3.我们可以重新缕一缕:看一下例子

**String str2=new String("sujintuan")+"sujin";//创建了多少个对象?(加上引用)**
3个:常量池:2个、堆中:1个;栈中1个引用
**图解:**

在这里插入图片描述
总结:
我们先是理一下自己的思想:方法区->常量池,栈、堆,存储地址。
我们在声明的是时候;无非就是 :
a.引用类型 类型名=值;
b.引用类型 类型名=new 引用类型();
第一种:直接定义声明;那么就不用理会堆区;它的存储过程是,再栈中生成一个存储空间,然后再到常量池寻找;是否存在这个字符值;如果不存在开辟一个空间存储。
第二种:引用再栈中,然后new 对象在堆中,开辟一个空间,在常量池中如果存在它的对象值,则直接使用内存地址赋值给堆中的对象。(这是我的理解……)

### Java String 常量池的工作原理及作用 #### 工作原理 在 Java 中,`String` 是一种特殊的对象类型,其不可变性和常量池机制是为了优化内存使用和提升程序性能而设计的。当创建一个 `String` 对象时,如果该字符串已经存在于常量池中,则不会重新分配内存空间来存储相同的值,而是直接返回已存在的引用[^1]。 具体来说,Java 的字符串常量池主要由两部分组成: - **静态常量池**:这是在编译阶段形成的,在 `.class` 文件中有对应的结构表示。 - **运行时常量池**:这是在 JVM 加载类之后形成的一种数据结构,位于方法区内存区域。它不仅包含了静态常量池的内容,还可以动态加入新生成的字符串实例[^4]。 以下是关于字符串常量池的一些关键行为: 1. 当通过字面量方式定义字符串(如 `String str = "abc";`),JVM 会先检查字符串常量池是否存在相同内容的对象。如果存在则重用已有对象;否则将其添加到池中并返回相应引用[^3]。 2. 使用 `new String()` 构造器显式创建字符串时,会在堆上开辟一块独立的空间存放此字符串,并不自动将其实例化版本放入常量池中。因此即使两个变量都指向同一个字面意义上的字符串,它们仍然可能代表不同地址上的实体[^2]。 3. 方法 `intern()` 可以手动干预这一过程——调用某个非池化的字符串实例的 `intern()` 函数后,若发现当前字符串尚未驻留于全局共享表里,则会被复制一份进去供后续查找匹配之需[^4]。 #### 作用 引入字符串常量池的主要目的是为了节省资源消耗以及加速比较操作: - **减少重复占用**: 如果多个地方需要用到完全一致的文字序列表达形式的话,那么只需要保存单一副本即可满足需求. - **加快相等判断速度**: 因为基于引用对比(`==`)要比逐字符逐一核验效率高得多所以只要确认两者确实来自同一份原始资料就足以得出结论. ```java // 示例代码展示 intern() 功能 public class Main { public static void main(String[] args) { String a = new StringBuilder("计算机").append("软件").toString(); System.out.println(a.intern() == a); // 输出 true String b = new StringBuilder("ja").append("va").toString(); System.out.println(b.intern() == b); // 输出 false (因为"java"已经在加载时进入了常量池) } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值