String,StringBuilder,StringBuffer都是用于处理字符串的类
String
核心特点
- 不可变:一旦创建就不可更改。任何的修改操作(字符串拼接,替换)都是产生一个新的对象
- 线程安全:因为不可变的特点,天然就是线程安全的
- 每次修改都会创建一个新的对象,大量频繁修改的情况下,会导致内存压力
- 内存中的字符串常量池,用于存储已有的字符串信息。创建时先去常量池查找,没有才会创建,以减轻内存压力
使用场景
适用于字符串不会频繁修改的场景。(常量,配置信息等)
多线程的场景下,不适合用String对象作为同步锁。字符串在常量池中是共享信息,可能会带来不必要的线程阻塞。
String s = "Hello";
s = s + " World"; // 生成新对象,原对象可能被GC回收
StringBuilder
核心特点
- 是可变的,StringBuilder内部有一个数组(byte[])来存放字符串信息。修改字符串并不会创建新的对象
- 是非线程安全的,没有使用线程同步的机制
使用场景
在单线程环境下,字符串频繁修改适合用 StringBuilder (例如:循环拼接字符串,SQL语句动态拼接等)
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 原地修改,无新对象生成
String result = sb.toString();
StringBuffer
核心特点
- 是可变的,同 StringBuilder 一样,内部维护了一个数组(byte[]),修改字符串不会创建新的对象
- 是线程安全的,synchronized修饰其中的方法。多线程情况下,同时只能有一个线程对字符串进行修改
- 因为添加了锁,所以性能上没有 StringBuilder 好
使用场景
适合在多线程环境下,需要对同一个字符串进行修改的场景
注意事项
StringBuilder 和 StringBuffer 完成对字符串的修改后,调用 toString() 方法,是创建了一个新的数组对字符串进行编码后,创建了一个String对象返回
后续如果再对 StringBuilder 和 StringBuffer 进行字符串修改,最新的修改不会影响已经调用 toString() 返回的String对象
源码
// StringBuilder 中的 toString() 方法
public String toString() {
// Create a copy, don't share the array
return isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value, 0, count);
}
// StringLatin1 或 StringUTF16 中的 newString() 方法
public static String newString(byte[] val, int index, int len) {
return new String(Arrays.copyOfRange(val, index, index + len),
LATIN1);
}
示例
public class BaseDataTypeTest {
public static void main( String[] args ) {
StringBuilder buil = new StringBuilder( );
buil.append( "builder" ).append( "String" );
String str = buil.toString();
System.out.println("before----str:" + str);
buil.append( "success" );
System.out.println("after----str:" + str );
System.out.println("after----buil:" + buil );
}
}