字符串的存储
字符串是一个字面量,它的值存储在常量池中(也就是方法区的运行时常量池),他的底层是使用字符数组来存储,它是可以共享的。以下展示直接字符串与字符串对象的存储。
其中String s1 = “ab”;会产生一个对象,也就是它底层的字符数组。
单独的String s2 = new String(“ab”);是会产生两个对象的,也就是堆内存中new出来的对象,和字符数组。
如果两个同时创建则只会产生两个对象,也就是字符数组和堆内存中new出来的对象。至于方法区的常量池中的字面量和字符数组会共享。
字符串的拼接
public class StringDemo1 {
public static void main(String[] args) {
// String s1 = "abc";
// s1 = "def";
// 指向常量池
String s1 = "ab";
// 指向堆内存
String s2 = new String("ab");
// "a"和"b"是两个字面量
// 两个字面量在运算的时候为了提高效率,在编译的时候会进行自动的计算优化
// byte b = 3 + 5; -> byte b = 8;
// String s3 = "ab";
String s3 = "a" + "b";
// 字符串在使用+拼接的时候底层实际上是调用了StringBuilder中的append方法
String s4 = "a";
// s4 = new StringBuilder(s4).append("b").toString();
// s4 = new String("ab");
s4 = s4 + "b";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1 == s4);
System.out.println(s2 == s4);
}
}
这里需要注意几个点:
①两个字面量在运算的时候为了提高效率,在编译的时候会进行自动的计算优化。也就是在写出String str = “a” + “b”; 和String str = “ab”;的编译完成时的效果是一样的。
②当以new的形式去创建一个字符串的时候,指针直接指向的地址是堆内存中的地址。
③当变量和常量进行相加的时候是不会再编译期自动运算的。而是创建一个StringBuilder然后在后面追加一个字符串,然后再new一个新的对向也就是它的toString方法。最后指向的是这个toString之后所new的对象。
这里就详细说明一下字串的拼接步骤如下:
String str = “a”;
String str1 = “b”;
str = str + str1;
①new StringBuilder(“a”); // 这时会产生一个新的对象
②.append(“b”);// append完成之后就又会产生一个对象
③.toString();// 这时会new一个String的对象。
前前后后涉及到了5个对象也就是拼接好一次需要多产生3个对象。
那么这个过程直接用StringBuilder的append呢?
也就是上述过程的②③步骤,会多产生2个对象。需要注意的是StringBuilder只是在最后一次toString一把而在使用+的时候每次连接都会toString一把。