java 常量池

常量池用于保存在编译期已确定的,已编译的,class文件中的一份数据,它包括了关于类,方法,接口等中的常量,也包括字符串常量。如第一种声明方式,当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。

用new String()创建的字符串不是常量,不能在编译期就确定,所以new String()创建的字符串不放入常量池中,他们有自己的地址空间。

String  s1 = “text”;

String s2 = “text”;

String s2 = s2+"java";

s1,s2同时指向常量池中的常量值"text",s2=s2+"java",后,s2原先指向一个常量,内容"text”,通过对s2进行+操作后,s2所指向的那个值没有改变,此时s2不指向原来那个变量值了,而指向了另一个String变量,内容为”text java“。原来那个变量还存在于内存之中,只是S2这个变量不再指向他了。

String 对象(内存)的不变性机制会使修改String字符串时,产生大量的对象,因为每次改变字符串,都会生成一个新的String。

java 为了更有效的使用内存,jvm有一块特殊的内存区域,被称为常量池,当编译期遇见String 字符串时,他检查该池内是否已经存在相同的String 字符串,如果找到,就把新变量的引用指向现有的字符串对象,不创建任何新的String 常量对象,没找到再创建新的。所以对一个字符串对象的任何修改,都会产生一个新的字符串对象,原来的依然存在,等待垃圾回收。


如果反汇编以上程序的字节码,可以发现,String a = b + "love"; 的实际实现是:
String a = new StringBuilder().append(b).append("love").toString();
所以其实最后是通过toString()方法返回的对象
再查看API中toString()方法的源代码
可以得出结论,返回的是一个堆中的新的对象

 String xx = "ab";

xx = xx + "cd"; //返回的是一个堆中的新的对象

String x1 = "abcd";//常量池中的对象

所以 if(xx == x1)  xx 和 x1 是不同的对象

String b = "hate";
String a = b + "love";
总共创建3个对象,分别是常量池中的“hate”和“love”,以及堆中的“hatelove”
执行过程分析:
1.类加载时,常量池中创建了2个字符串字面常量"hate"和"love"
2.栈中创建引用b,指向常量池中的"hate"
3.栈中创建引用a,+运算后,堆中创建String对象"hatelove",引用a指向该对象


Integer(http://www.iteye.com/topic/1112923)

和String的对象池一样,几种整数基本类型的包装类型也有对象池机制。 
也就是说用Integer int1 = 30;这种方式声明一个Integer对象时会先在对象池中找有没有值为30的对象,如果有直接拿来用,如果没有则重新创建一个对象放入对象池中。java中“==”是比较值,int1和int2引用的同一个对象,内存地址相同,所以int1==int2结果为true。 
而Integer int4 = new Integer(30);这种方式是重新创建一个Integer对象,不会放入对象池中,所以int4和int5是两个不同对象的引用int4==int5结果为false。 
至于int4==int5+int6,因为涉及到运算,所以都是取的各个Integer对象的intValue,也就是比较的30==30+0,所以为true。 
另外补充一点,对象池中对象的值的在[-128,127]之间,超过此范围的不会在对象池中缓存。也就是说Integer int7 = 130;Integer int8 = 130;判断int7==int8,结果为false。

 

Integer int1 = 30; 
Integer int2 = 30; 
Integer int3 = 0; 
System.out.println(int1 == int2); 
System.out.println(int1 == int2 + int3); 

Integer int4 = new Integer(30); 
Integer int5 = new Integer(30); 
Integer int6 = new Integer(0); 
System.out.println(int4 == int5); 
System.out.println(int4 == int5 + int6); 

Java 开发中,常量池是一个至关重要的概念,贯穿于程序的编译、加载以及运行过程,不同版本的 JVM 中,常量池是优化内存使用和提高性能的重要机制。以 JDK 11 为例,常量池主要包括静态常量池、运行时常量池、基础常量池和字符串常量池 [^1][^2]。 ### Class 常量池 Class 常量池是 .java 文件编译后的静态信息,它主要包括字面量和符号引用。例如以下代码: ```java public class ClassConstantTest { private final String name = "Tom"; private final int age = 18; private String sk = "sk.com"; private int salary = 10000000; public String getName() { return name; } public int getAge() { return age; } public String getSk() { return sk; } public int getSalary() { return salary; } } ``` 此代码编译后的 Class 文件常量池含了 `name`、`age` 等字面量,以及方法名、名等符号引用 [^1][^3]。 ### 运行时常量池 当 Class 常量池的信息在运行时被加载到内存后,就变成了运行时常量池。对应的符号引用在程序加载或运行时会被转变为被加载到内存区域的代码的直接引用,即动态链接。例如,某个符号引用在运行时会被转变为具体代码在内存中的地址,主要通过对象头里的型指针去转换直接引用 [^4]。 ### 字符串常量池 字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。作为最基础的数据型,大量频繁的创建字符串,会极大程度地影响程序的性能。JVM 为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为字符串开辟一个字符串常量池似于缓存区。创建字符串常量时,首先查询字符串常量池是否存在该字符串。若存在该字符串,返回引用实例;若不存在,则实例化该字符串并放入池中 [^4]。 ### 静态常量池 静态常量池Java 常量池的一种,它存储了的相关静态信息,是常量池机制的一部分,有助于 JVM 对信息的管理和使用 [^2]。 ### 基础常量池Java JVM 中,基础常量池也是常量池的一部分,不过引用中未详细提及它的具体内容 [^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值