String
- 不可变性:
String
是不可变的,一旦创建就不能修改。每次对String
的修改(如拼接)都会创建一个新的String
对象。 - 性能:由于每次修改都会创建新的对象,如果频繁进行字符串拼接,性能会较差。特别是在循环中使用时,可能会导致性能问题。
- 线程安全:
String
是线程安全的,因为它是不可变的。
不同情况下String到底会创建几个对象
String有两种创建方式:
1. String s = "abc"; 会创建0或1个对象。如果"abc"在字符串常量池里没有,就创建1个,如果存在,就创建0个对象
2. String s = new String("abc"); 会创建1个或2个对象。
String s = ”ab"+"c",那编译器会自动连接,String s = ”abc",见1
String s1 = “ab"; String s2 = “c"; String s = s1+s2; 这个时候还得创建一个StringBuilder对象,调用append方法连接,所以String s = s1+s2会创建一个对象
String s = new String(s1+s2); 创建2个对象,一个是new出来的String对象,一个是底层的StringBuilder对象
String为什么是不可变的
看看源码
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
//...
}
被 final
关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final
关键字修饰的数组保存字符串并不是 String
不可变的根本原因,因为这个数组保存的字符串是可变的(final
修饰引用类型变量的情况)。因为value是个引用,指向这个数组,final修饰是这个指向(也就是指针)不能变了,并不是value数组里面的内容不能变了
String
真正不可变有下面几点原因:
- 保存字符串的数组被
final
修饰且为私有的,并且String
类没有提供/暴露修改这个字符串的方法。 String
类被final
修饰导致其不能被继承,进而避免了子类破坏String
不可变。
字符串拼接用“+” 还是 StringBuilder?
Java 语言本身并不支持运算符重载,“+”和“+=”是专门为 String 类重载过的运算符,也是 Java 中仅有的两个重载过的运算符。字符串对象通过“+”的字符串拼接方式,实际上是通过 StringBuilder
调用 append()
方法实现的,拼接完成之后调用 toString()
得到一个 String
对象 。
StringBuilder
- 可变性:
StringBuilder
是可变的,可以修改其内容而不创建新的对象。适用于需要对字符串进行频繁修改的场景。 - 性能:由于其内容是可变的,不会创建新的对象,因此在进行大量字符串拼接操作时,性能优于
String
。 - 线程安全:
StringBuilder
不是线程安全的。它不适用于多线程环境下的字符串操作。
StringBuffer
- 可变性:
StringBuffer
也是可变的,与StringBuilder
类似,可以修改其内容而不创建新的对象。 - 性能:
StringBuffer
的性能与StringBuilder
类似,但通常略低,因为它的操作涉及更多的同步。 - 线程安全:
StringBuffer
是线程安全的。它的方法是同步的,因此可以在多线程环境下安全地使用。
\TODO 常用的API