1. Java中String和String Pool
class="java">
1. 采用字面值方式赋值
String str = "aaa";
String str2 = "aaa";
System.out.println(str == str2);返回结果为true。
1) 查找String Pool中是否存在"aaa"这个对象,如果不存在,则在String Pool中创建一个"aaa"对象,然后将StringPool中的这个"aaa"对象的地址返回来,赋给引用变量str,这样str会指向String Pool中的这个"aaa"字符串对象。
2) 如果存在,则不创建任何对象,直接将String Pool中的这个"aaa"对象地址返回来,赋给s引用。
2. 采用new关键字新建一个字符串对象
String str = new String("aaa");
String str2 = new String("aaa");
System.out.println(str == str2);返回结果为false。
(1) 首先在String Pool中查找有没有"aaa"这个字符串对象,如果有,则不在String Pool中再去创建"aaa"这个对象了,直接在堆中(heap)中创建一个"aaa"字符串对象,然后将堆中(heap)的这个"aaa"对象的地址返回来,赋给str引用,使str指向堆中创建的这个"aaa"字符串对象。
(2) 如果没有,则首先在String Pool中创建一个"aaa"对象,然后再在堆中(heap)创建一个"aaa"对象,然后将堆中的这个"aaa"对象的地址返回来,赋给str引用,使str指向堆中(heap)所创建的这个"aaa"对象。
3. intern()方法
如果String Pool中包含这个对象,则返回String Pool的中的对象。否则这个对象将添加到String Pool中。
如果a.equals(b)为true,则a.intern() == b.intern()返回结果为true。
4. 字符串池
字符串池的优缺点:
1) 字符串池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;
2) 另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。
Java语言的规范:
1) 每一个字符串常量都指向字符串池中或者堆内存中的一个字符串实例;
2) 字符串对象值是固定的,一旦创建就不能再修改;
3) 字符串常量或者常量表达式中的字符串都被使用方法String.intern()在字符串池中保留了唯一的实例;
public class Test {
public static void main(String[] args) {
Other other = new Other();
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ; ");
System.out.print((Other.hello == hello) + " ; ");
System.out.print((other.hello == hello) + " ; ");
System.out.print((hello == ("Hel" + "lo")) + " ; ");
System.out.print((hello == ("Hel" + lo)) + " ; ");
System.out.print((hello == ("Hel" + lo).intern()) + " ; ");
}
}
class Other {
static String hello = "Hello";
}
运行结果:
true ; true ; true ; true ; false ; true ;
(1) 同一个包下同一个类中的字符串常量的引用指向同一个字符串对象;
(2) 同一个包下不同的类中的字符串常量的引用指向同一个字符串对象;
(3) 不同的包下不同的类中的字符串常量的引用仍然指向同一个字符串对象;
(4) 由常量表达式计算出的字符串是在编译时进行计算,然后被当作常量;
(5) 在运行时通过连接计算出的字符串是新创建的,因此是不同的;
(6) 通过计算生成的字符串显示调用intern方法后产生的结果与原来存在的同样内容的字符串常量是一样的。
5. 字符串是常量,字符串池中的每个字符串对象只有唯一的一份,可以被多个引用所指向,避免了重复创建内容相同的字符串;通过字面值赋值创建的字符串对象存放在字符串池中,通过关键字new出来的字符串对象存放在堆中。
public class Test {
public static void main(String[] args) {
String test = "javastringtest";
String sub1 = "java";
String sub2 = "string";
String sub3 = "test";
System.out.println(test == "java" + "string" + "test");
System.out.println(test == sub1 + sub2 + sub3);
}
}
运行结果:
true
false
(1) 字符串字面量拼接操作是在Java编译器编译期间就执行了,也就是说编译器编译时,直接把"javastringtest","java","string"这三个字面量进行"+"操作得到一个"javastringtest"常量,并且直接将这个常量放入字符串池中,这样做实际上是一种优化,将3个字面量合成一个,避免了创建多余的字符串对象。
(2) 而字符串引用的"+"运算是在Java运行期间执行的,即ub1+sub2+sub3在程序执行期间才会进行计算,它会在堆内存中重新创建一个拼接后的字符串对象。
(3) 字面量"+"拼接是在编译期间进行的,拼接后的字符串存放在字符串池中;
而字符串引用的"+"拼接运算实在运行时进行的,新创建的字符串存放在堆中。