一、基本概念
String:字符串常量,字符串长度不可变。java中String是immutable(不可变的)。用于存放字符的数组被声明为final,因此只能赋值一次,不可再更改。

StringBuffer:字符串变量(Synchronized,线程安全)。如果要频繁的对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型学,可以调用StringBuffer的toString()方法。java.lang.StringBuffer线程安全可变字符序列。在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。

StringBuilder:字符串变量(非线程安全)。

二、基本原则:
1)如果要操作少量的数据用String。
2)单线程操作大量数据用StringBuilder;
3)多线程操作大量数据用StringBuffer;

三、String类不可变解析说明:

String s = "hello";
System.out.println(s);
s = "world";
System.out.println(s);

运行结果:

hello
world

虽然从结果上看来发生了改变,其实实例中的s只是一个String对象的引用,并不是对象本身,当执行s = “world”;时创建了一个新的“world”,而原来的“hello”依然存在与内存中。
字符串实际上就是一个char数组,并且内部就是封装了一个char数组。并且这里char数组是被final修饰的。并且String中的是所有的方法,都是对于char数组的改变,只要是对它的改变,方法内部都是返回一个新的String实例。

四、举例

1)

String str1 = "aa"; //常量池
String str2 = new String("aa"); //堆内存中
System.out.println(str1 == str2); //false 两个对象的地址值不一致
System.out.println(strl.equals(str2)); // true



String str1 = "a"+"a";
String str2 = "aa";
System.out.println(str1 == str2);//true  java中常量化机制,编译str1时已经成为aa在常量池中查找创建,str2不需要再创建。
System.out.println(str1.equals(str2));//true

3)

String str1 = "a";
String str2 = "aa";
String str3 = str1 + "a";
System.out.println(str3 == str2); //false
System.out.println(str3.equals(str2));//true

说明:现在常量池中创建a,地址指向str1,再创建aa,地址指向str2。对于str3,先创建StringBuilder(或StringBuffer)对象,通过append连接得到aa,调用toString()转换得到的地址指向str3。故(str3==str2)为false。

4)

String str1 = "hello world";
String str2 = new String("hello world");
String str3 = "hello world";
String str4 = new String("hello world");
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//true
System.out.println(str1 == str4);//false

说明:String str1 = “hello world” 和 String str3 = "hello world"都在编译期间生成了字面常量和符号引用,运行期间字面常量“hello world”被存储在运行时常量池(只存一份)。通过这种方式来将String对象跟引用绑定,JVM执行引擎会实现在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。

小结:Java 中 StringBuffer 和 String 是有一定的区别的,首先,String 是被 final 修饰的,他的长度是不可变的,就算调用 String 的 concat 方法,那也是把字符串拼接起来并重新创建一个对象,把拼接后的 String 的值赋给新创建的对象,而 StringBuffer 的长度是可变的,调用StringBuffer 的 append 方法,来改变 StringBuffer 的长度,并且,相比较于 StringBuffer,String 一旦发生长度变化,是非常耗费内存的。