字符串常量池
1.定义:字符串常量池(String Constant Pool),用于存放字符串常量的运行时内存结构,其底层的实现为Hashtable。
【注意】
-
在JDK1.6之前,字符串常量池中只会存放具体的String实例,在使用String.intern方法时,若字符串常量池中有满足String.equals方法的String对象,则返回其引用;字符串常量池中没有相同的String对象,则当前String对象为堆上对象,故在字符串常量池中创建一个相同的String对象,并返回其引用。
-
在JDK1.7之后,字符串常量池不仅可以存放String实例,同时还能存放String实例的引用。在使用String.intern方法时,若字符串常量池中有满足String.equals方法的String对象,则返回其引用,这一点和JDK1.6相同;若字符串常量池中没有相同的String对象,则当前String对象为堆上对象,故在字符串常量池中存放一个指向堆上此String对象的引用,并返回此引用。
代码例子1:
public class Test {
public static void main(String[] args) {
String s1 = new String("He") + new String("llo");// 堆上创建"Hello","He","llo"实例,String Pool中创建"He"和"llo"实例
s1.intern();// 将堆上"Hello"的引用存入String Pool
String s2 = "Hello";// 获取String Pool中的"Hello"的引用
System.out.println(s1 == s2);// true
}
}
代码例子2:
public class Test {
public static String s = "Hello";
public static void main(String[] args) {
String s1 = new String("He") + new String("llo");
// 堆上创建"Hello","He","llo"实例,String Pool中创建"He"和"llo"实例
s1.intern();
// String Pool中已有"Hello",故没有将s1的引用添加到String Pool中,返回的是String Pool中已有的"Hello"的引用
String s2 = "Hello";
// 获取String Pool中的"Hello"的引用
System.out.println(s1 == s2);// false
System.out.println(s == s2);// true
}
}
字符串常量池在JVM的分布
参考《深入理解Java虚拟机》
intern方法
参考地址见文末
例子
//字符串常量池:"计算机"和"技术"
//堆内存:str1引用的对象"计算机技术"
//堆内存中还有个StringBuilder的对象,但是会被gc回收
//StringBuilder的toString方法会new String(),这个String才是真正返回的对象引用
String str2 = new StringBuilder("计算机").append("技术").toString(); //字面量没有出现"计算机技术"字面量,所以不会在常量池里生成"计算机技术"对象
//"计算机技术" 在池中没有,但是在堆中存在,则intern时,会直接返回该堆中的引用
System.out.println(str2 == str2.intern()); //true
//字符串常量池:"ja"和"va"
//堆内存:str1引用的对象"java"
//堆内存中还有个StringBuilder的对象,但是会被gc回收
//StringBuilder的toString方法会new String(),这个String才是真正返回的对象引用
String str1 = new StringBuilder("ja").append("va").toString(); //没有出现"java"字面量,所以不会在常量池里生成"java"对象
//java是关键字,在JVM初始化的相关类里肯定早就放进字符串常量池了
System.out.println(str1 == str1.intern()); //false
//"test"作为字面量,放入了池中
//而new时s1指向的是heap中新生成的string对象
//s1.intern()指向的是"test"字面量之前在池中生成的字符串对象
String s1=new String("test");
System.out.println(s1==s1.intern()); //false
String s2=new StringBuilder("abc").toString();
System.out.println(s2==s2.intern()); //false
//同上
参考链接:
https://blog.51cto.com/u_15281317/3008750
https://code84.com/21914.html