一篇文章帮助你理解Java StringBuffer 和 StringBuilder 的区别和使用场景
上篇文章我们说到在 Java 中,String 类是不可变的,也就是说一旦创建了 String 对象,它的值就无法改变。
当你修改一个字符串时,实际上是创建了一个新的字符串对象,而原始的字符串对象保持不变。
原因是: String 类使用了字符数组来存储字符串的值,并且该字符数组是被声明为 final 的,即不可修改的。
通过下面的例子可以帮助我们快速理解:
String str = "Hello";
str = str + ", World!";//新建一个对象在内存池中,并且将地址指引指向str
在这段示例中,“Hello” 字符串对象是通过字符串字面量创建的,而 “+”, “, World!” 和最终的结果字符串 “Hello, World!” 则是通过字符串拼接操作创建的。
具体的创建过程如下:
创建 “Hello” 字符串对象:
- JVM 在常量池中搜索是否存在值为 “Hello” 的字符串对象。
- 如果不存在,则在常量池中创建一个新的字符串对象,并将其值设置为 “Hello”。
- 如果已经存在,则直接引用已存在的字符串对象。
执行字符串拼接操作:
- 创建一个 StringBuilder 对象,在其中存储拼接后的字符串结果。
- 将原始的字符串 “Hello” 复制到 StringBuilder 对象中。
- 将字符串 “, World!” 追加到 StringBuilder 对象中。
- 调用 StringBuilder 对象的 toString() 方法,将其转换为一个新的 String 对象。
- 将新的字符串对象赋值给变量 str。
PS:因为 String 类是不可变的,原始字符串对象的值不会改变。
这种不可变性有一些好处,例如:
- 字符串可以被安全地用作方法参数,因为你不必担心其值被修改。
- 可以在多线程环境下共享字符串对象,而无需担心竞态条件。
**因为,Java 中的字符串拼接操作可能会产生大量的临时对象,因此在进行大量字符串拼接的情况下,也就是需要频繁地对字符串进行修改操作,可以考虑使用 StringBuilder 或 StringBuffer 类来提高性能,它们提供了可变字符串的功能。 **
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
StringBuilder 和 StringBuffer 是用于处理可变字符串的类,它们有一些相似之处,但也有一些区别。
1.可变性:
- StringBuilder:是非线程安全的,可以进行高效的字符串拼接和修改操作。StringBuilder 进行字符串修改时,不会创建新的对象,而是直接在原有对象上进行操作,因此适用于单线程环境。
- StringBuffer: 是线程安全的,可以在多线程环境下使用,但相对于 StringBuilder,其性能稍差。StringBuffer 的所有公共方法都被 synchronized 关键字修饰,保证了线程安全性。
2.性能:
StringBuilder:由于不需要考虑线程安全,StringBuilder 的性能比 StringBuffer 更好。因为 StringBuilder 不执行同步操作,所以在大多数情况下,使用 StringBuilder 都是更好的选择。
3.操作:
**共同点:**StringBuilder 和 StringBuffer 提供了类似的方法,如 append()、insert()、delete()、replace() 等用于字符串操作的方法。
**差异点:**StringBuffer 还提供了额外的方法,如 ensureCapacity() 和 setLength(),用于调整容量和长度。
根据上述特点和区别,可以根据需求选择适当的类:
- 如果在单线程环境中进行大量字符串拼接或修改操作,建议使用 StringBuilder,以获得更好的性能。
- 如果在多线程环境中进行字符串操作,应选择 StringBuffer,并且需要注意线程安全性。
示例用法:
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(", World!");
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("Hello");
stringBuffer.append(", World!");
在平常的开发中,一般情况下使用 StringBuilder 就可以满足要求。只有在多线程环境或者对线程安全有要求的情况下,才需要使用 StringBuffer。
StringBuilder 和 StringBuffer 类提供了一系列用于字符串操作的方法。下面是它们的常用方法:
- append(String str):在字符串的末尾追加指定的字符串。
- insert(int offset, String str):在指定位置插入指定的字符串。
- delete(int start, int end):删除指定范围内的字符。
- replace(int start, int end, String str):用指定的字符串替换指定范围内的字符。
- substring(int start):获取从指定位置开始到字符串结尾的子串。
- substring(int start, int end):获取指定范围内的子串。
- length():返回字符串的长度。
- capacity():返回当前容量(字符缓冲区的大小)。
- ensureCapacity(int minCapacity):确保容量至少为指定值。
- setLength(int newLength):设置字符序列的长度。
- indexOf(String str):返回第一次出现指定字符串的索引。
- lastIndexOf(String str):返回最后一次出现指定字符串的索引。
- reverse():将字符串反转。
- toString():将 StringBuilder 或 StringBuffer 对象转换为 String 对象。
示例用法:
public class Main {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("大家"); // 在字符串的末尾追加指定的字符串
sb.append("好!"); // "大家好!"
sb.insert(2, ","); // 在指定位置插入指定的字符串,结果为 "大家,好!"
sb.delete(1, 3); // 删除指定范围内的字符,结果为 "大,好!"
sb.replace(2, 4, "朋友们"); // 用指定的字符串替换指定范围内的字符,结果为 "大朋友们好!"
String subString = sb.substring(1, 5); // 获取指定范围内的子串,结果为 "朋友们"
int length = sb.length(); // 字符串的长度为 7
int index = sb.indexOf("大"); // 第一次出现 "大" 的索引为 0
sb.reverse(); // 反转字符串,结果为 "!好们友朋大"
String result = sb.toString(); // 将 StringBuilder 对象转换为 String 对象
System.out.println(result); // 输出结果为 "!好们友朋大"
}
}
结尾语:记录于2023年7月22号15时20分,以上仅为个人在菜鸟教程Java StringBuffer的学习过程中遇到的问题,还有记录的个人想法,有错误欢迎指出,感谢