一、String、StringBuffer、StringBuilder有什么区别?
String、StringBuffer、StringBuilder区别如下:
- 线程安全性:
String线程安全(因为不可变),StringBuffer线程安全(因为方法都加了synchronized锁),StringBuilder线程不安全(因为没有加锁) - 性能:
String性能最差(每次更新都要创建一个新对象),StringBuffer性能一般(每次更新只需要原地操作),StringBuilder性能较好(相比StringBuffer较好,但是要承担线程不安全的风险) - 可变性:
String不可变(重新赋值会创建新对象),StringBuffer和StringBuilder可变(都继承AbstractStringBuilder,提供了如append方法支持修改字符串)abstract class AbstractStringBuilder implements Appendable, CharSequence { char[] value; int count; public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); // 检查数组容量是否足够,如果不够则扩容 ensureCapacityInternal(count + len); // 复制str从0到len-1的字符串到value的count开始处 str.getChars(0, len, value, count); // 修改字符串长度 count += len; return this; } }
二、String为什么是不可变的?
因为String的底层存储用的是char[],而且用了final修饰,说明不可变相关代码为:
public final class String implements Serializable, Comparable<String>, CharSequence {
private final char value[];
}
总结,String不可变的原因是:
value[]被private final修饰,而String没有提供修改value[]的方法String被final修饰所以不能被继承,避免子类破坏String不可变
另外提一嘴,在JDK 9之后,String的底层存储由char[]改为了byte[],目的是减少内存占用(具体为什么可百度)。
三、如何更好地拼接多个字符串?
一般情况下,如果要拼接多个字符串,我们是直接使用+来操作,如下:
String str1 = "Hello";
String str2 = "World";
String str3 = "!";
String str4 = str1 + str2 + str3;
实际中,调用+操作时,底层还是通过StringBuilder的append()方法去拼接的,但是会出现一个问题:每拼接一个字符串都需要创建一个StringBuilder,如果拼接的字符串数量过大,那么会创建大量的StringBuilder,导致性能问题
所以一般我们直接借用StringBuilder来进行字符串拼接,而不是String拼接String,那么就会解决这个问题了,代码如下:
String str1 = "Hello";
String str2 = "World";
String str3 = "!";
//String str4 = str1 + str2 + str3;
StringBuilder s = new StringBuilder(;)
s.append(str1);
s.append(str2);
s.append(str3);
另外提一嘴,在JDK 9之后,使用+拼接字符串导致创建大量StringBuilder的问题已经被解决了(通过调用makeConcatWithConstants()方法)