String str2 = new String("ABC");
上面语句创建了几个字符串对象?上面语句实际上创建了2个字符串对象,一个是“ABC”这个直接量对应的对象,一个是new String()构造器返回的字符串对象。
在JVM里,考虑到垃圾回收(Garbage Collection)的方便,将heap(堆)划分为三部分:young generation(新生代)、tenured generation (old generation)(旧生代)、permanent generation(永生代)。
字符串为了解决字符串重复问题,生命周期长,存于pergmen中。
String str1 = “ABC”;可能创建一个或者不创建对象,如果”ABC”这个字符串在java String池里不存在,会在JVM的字符串池里创建一个创建一个String对象(“ABC”),然后str1指向这个内存地址,无论以后用这种方式创建多少个值为”ABC”的字符串对象,始终只有一个内存地址被分配,之后的都是String的拷贝,Java中称为“字符串驻留”,所有的字符串常量都会在编译之后自动地驻留。
String str2 = new String(“ABC”);至少创建一个对象,也可能两个。因为用到new关键字,肯定会在heap中创建一个str2的String对象,它的value是“ABC”。同时如果这个字符串再java String池里不存在,会在java池里创建这个String对象“ABC”。
public class Test2 {
public static void main(String[] args) {
String s1 = new String("ABC");
String s2 = new String("ABC");
System.out.println(s1 == s2);//false
System.out.println(s1.equals(s2));//true
}
}
如果将一个字符串连接表达式赋给字符串变量,如果这个字符串连接表达式的值可以在编译时就确定下来,那么JVM会在编译时确定字符串变量的值,并让它指向字符串池中对应的字符串。
但是如果程序使用了变量或者调用了方法,那就只有在运行时才能确定该字符串表达式的值,因此无法在编译时确定值,无法利用JVM的字符串池。
public class Test2 {
public static void main(String[] args) {
String s1 = "ABCDEF";
String s2 = "ABC" + "DEF";
System.out.println(s1 == s2);//true,可以在编译时确定
String s3 = "DEF";
String s4 = "ABC" + s3;
System.out.println(s1 == s4);//false,无法在编译时确定
final String S5 = "DEF";
String s6 = "ABC" + S5;
System.out.println(s1 == s6);//true,使用final关键字,在编译时将对S5进行宏替换
}
}
当程序中需要使用字符串、基本数据类型包装实例时,应该尽量使用字符串直接量、基本数据类型的直接量,避免通过new String()、new Integer()等形式来创建字符串、基本数据类型包装类实例,这样能保证较好的性能。