对于java程序中的字符直接量,JVM会使用一个字串池来保存它们。当第一次使用某个字符串直接量时,JVM会将它放入字符串池中进行缓存。在一般情况下,字符串池中的字符串对象不会被垃圾回收。当程序再次需要使用该字符串时,无需重新创建一个新的字符串就可以直接让引用变量直接指向字符串中已有的字符串。而使用new操作创建的字符串对象不指向字符串池中的对象,但是可以使用intern方法使其指向字符串池中的对象。
public class StringDemo { public static void main(String args[]){ String str1 = "abc"; String str2 = "abc"; String str3 = "def"; String str4 = "abcdef"; String str5 = "abc" + "def";//在字符串池中能找到“abcdef”对象,故str5 == str4 为true String str6 = str2 + str3;//在运行时才知道,也就是说str1+str2是在堆里创建的 String str7 = new String("abcdef");//new操作创建的字符串对象不指向字符串池中的对象 String str8 = str7.intern();//使用intern方法使str7指向的对象加入字符串池中 if(str1 == str2){ System.out.println("此时str1引用变量与str2引用变量" + "是指向在字符串池中的同一个内存块"); }else{ System.out.println("此时str1引用变量与str2引用变量" + "不是指向在字符串池中的同一个内存块"); } if(str4 == str5){ System.out.println("此时str4引用变量与str5引用变量" + "是指向在字符串池中的同一个内存块"); }else{ System.out.println("此时str4引用变量与str5引用变量" + "不是指向在字符串池中的同一个内存块"); } if(str4 == str6){ System.out.println("此时str4引用变量与str6引用变量" + "是指向在字符串池中的同一个内存块"); }else{ System.out.println("此时str4引用变量与str6引用变量" + "不是指向在字符串池中的同一个内存块"); } if(str4 == str7){ System.out.println("此时str4引用变量与str7引用变量" + "是指向在字符串池中的同一个内存块"); }else{ System.out.println("此时str4引用变量与str7引用变量" + "不是指向在字符串池中的同一个内存块"); } if(str4 == str8){ System.out.println("此时str4引用变量与str8引用变量" + "是指向在字符串池中的同一个内存块"); }else{ System.out.println("此时str4引用变量与str8引用变量" + "不是指向在字符串池中的同一个内存块"); } } }
输出: 此时str1引用变量与str2引用变量是指向在字符串池中的同一个内存块 此时str4引用变量与str5引用变量是指向在字符串池中的同一个内存块 此时str4引用变量与str6引用变量不是指向在字符串池中的同一个内存块 此时str4引用变量与str7引用变量不是指向在字符串池中的同一个内存块 此时str4引用变量与str8引用变量是指向在字符串池中的同一个内存块
因为字符串池中的字符串对象不会被垃圾回收,所以当某个字符串池中的字符串对象失去引用时,它将变成垃圾,而字符串池又不回收。于是便产生了java内存泄露。示例如下:
public class AnotherStringDemo { public static void main(String args[]){ String str1 = "abc"; String str3 = "def"; str3 = str1 ; System.out.println(str3); System.out.println(str1); } }
输出:
abc
abc
("def"失去引用,将成为垃圾,进而内存泄露)