Java虚拟机之String Pool

String Pool 是一块用来专门存放String的堆内存。String类是一个特殊类,创建的对象是不可变的。创建方式可以使用 new 关键字创建,也可以使用双引号 ” ” 创建。
String Pool 有助于为Java Runtime节省大量空间,但需要更多时间来创建字符串以及查找。
这里写图片描述

1、使用 ” ” 创建String对象

1、直接使用 ” ” 申明

String s1 = "Cat";

使用 ” ” 创建String对象,JVM首先会在String Pool 中查找是否已经有该String,如有,直接返回常量池中的引用。若没有,则在String Pool 中创建该字符串并返回该引用。

JVM存在编译期优化,所以在编译的时候,”Cat” 就被存储在了常量池中。

2、使用 + 申明

String str = "a" + "b";

由于JVM存在编译期优化,对于两个直接双引号声明的String的 + 操作,JVM在编译期会直接优化为“ab”一个字符串。同String str = “ab”,效果是一样的。

3、使用String 变量申明

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

由于b是一个String变量,编译期无法确定b的值,所以不会优化为一个字符串。即使我们知道b的值,但JVM认为它是个变量,变量的值只能在运行期才能确定,所以不会优化。

运行期字符串的 + 连接符相当于 new,故该行代码在Heap中创建了一个内容为 “ab” 的String对象,并返回该对象的引用。因为没有直接双引号声明 ab 这2个字符的字符串,故常量池中不会生成 ab 这2个字符的字符串。但是会有 “a” 和 “b” 这两个String对象,因为他们都用双引号声明了。

String a = "a";  
String b = a + "b";
String c = "ab";
System.out.println(b == c);

输出false。

4、加 final 修饰

final String a = "a";  
String b = a + "b";

使用 final 修饰的变量为常量,所以在编译期JVM能确定b的值,所以对 + 可以优化为 “ab” 2个字符的字符串。所以在常量池中会同时存在 “a” 和 “ab” 。

final String a = "a";  
String b = a + "b";
String c = "ab";
System.out.println(b == c);

输出true。

2、使用 new 创建String对象

String s3 = new String("Cat");

使用 new 来创建对象,都会在堆中创建一个新对象,然后返回该对象的引用。
对于该行代码生成了两个String对象。
第一步:由于使用了 ” “,所以首先在常量池中查找是否有了 Cat 字符串,若没有,则在常量池中创建字符串 Cat,然后进行下一步;若有了,则直接进行下一步。
第二步:由于使用了new,所以JVM会在Heap(堆)中创建一个内容相同的String对象,然后返回堆中String对象的引用。

所以该行代码分别在常量池和堆中创建了两个内容相同的String对象。

String s1 = "Cat";
String s3 = new String("Cat");   
System.out.println(s1==s3);

输出false。

3、intern( ) 方法

String.intern( ) 是一个Native方法,它的作用是:如果运行时常量池中已经包含一个等于此String对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中记录Java Heap中首次出现的该字符串的引用,并返回该引用。

JDK1.6 之前
当常量池中没有该字符串时,JDK16 的intern()方法的实现是在常量池中创建与此String内容相同的字符串,并返回该引用。

String s4 = "test";  
System.out.println(s4 == s4.intern());        

输出true。创建过程是先在常量池中创建字符串 “test”,然后返回该引用。

String s5 = new String("test");  
System.out.println(s5 == s5.intern()); 

输出false。由于使用了 ” “,所以会在常量池中创建 “test”,而 new 时,会在堆中新创建一个对象。s5指向堆中对象,s5.intern() 是常量池中的引用。

String s6 = new StringBuilder("a").append("b").toString();  
System.out.println(s6 == s6.intern());

输出true。ab在常量池中没有,但是在heap中存在,所以 intern 时,会直接返回该heap中的引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值