String、 StringBuffer 和 StringBuilder 的区别和作用及使用场景

StringStringBufferStringBuilder 是 Java 中常见的字符串操作类,它们主要的区别在于可变性线程安全性性能

1. 三者的主要区别

特性 String StringBuffer StringBuilder
是否可变 不可变(Immutable) 可变(Mutable) 可变(Mutable)
线程安全性 线程安全(但不可变,无需加锁) 线程安全内部使用 synchronized 关键字) 非线程安全
性能 性能最低(因每次修改都创建新对象) 性能较低(因线程安全同步机制) 性能最高
适用场景 适用于少量字符串拼接字符串内容不会变化的情况 适用于多线程环境下频繁修改字符串 适用于单线程环境下频繁修改字符串

2. 具体使用场景

使用场景 推荐的类
字符串内容不会变,如存储常量字符串(e.g. final String name = "Hello"; String
多线程环境,并且需要修改字符串(线程安全) StringBuffer
单线程环境,需要高效修改字符串 StringBuilder
字符串拼接较少,如 "Hello" + "World" String
大量字符串拼接(如循环中追加字符串) StringBuilder
需要线程安全的字符串操作(如日志记录) StringBuffer

3. 代码示例

(1) String(不可变对象)

public class StringTest {
    public static void main(String[] args) {
        String str = "Hello";
        str += " World";  // 创建了新的字符串对象 "Hello World"
        System.out.println(str);  // 输出: Hello World
    }
}

注意str += " World"; 会创建一个新的 String 对象,而不会修改原来的 str,这会导致大量的临时对象,影响性能。


(2) StringBuffer(线程安全,可变字符串)

public class StringBufferTest {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Hello");
        sb.append(" World");  // 直接修改sb对象,不创建新对象
        System.out.println(sb.toString());  // 输出: Hello World
    }
}

特点

  • 线程安全(内部方法使用 synchronized 关键字)。
  • 性能较 StringBuilder 低,但适用于多线程环境

(3) StringBuilder(非线程安全,高性能)

public class StringBuilderTest {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(" World");
        System.out.println(sb.toString());  // 输出: Hello World
    }
}

特点

  • 不使用 synchronized,所以性能更高
  • 适用于单线程环境。

4. 性能对比

测试 String、StringBuffer 和 StringBuilder 在循环拼接字符串时的性能

public class PerformanceTest {
    public static void main(String[] args) {
        int iterations = 100000; // 测试10万次字符串拼接

        // 1. 使用 String
        long startTime = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < iterations; i++) {
            str += i; // 每次循环都会创建新的字符串对象
        }
        long endTime = System.currentTimeMillis();
        System.out.println("String 耗时: " + (endTime - startTime) + " ms");

        // 2. 使用 StringBuffer
        startTime = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < iterations; i++) {
            sb.append(i);
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer 耗时: " + (endTime - startTime) + " ms");

        // 3. 使用 StringBuilder
        startTime = System.currentTimeMillis();
        StringBuilder sb2 = new StringBuilder();
        for (int i = 0; i < iterations; i++) {
            sb2.append(i);
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder 耗时: " + (endTime - startTime) + " ms");
    }
}

可能的输出结果

String 耗时: 12500 ms
StringBuffer 耗时: 15 ms
StringBuilder 耗时: 10 ms

分析:

  • String 拼接最慢,因为 str += i; 每次都会创建新对象,消耗大量时间。
  • StringBuffer 由于同步机制比 StringBuilder 略慢
  • StringBuilder 最快,适合单线程环境的字符串操作。

5. StringBuffer 和 StringBuilder 常用方法

方法 说明 示例
append(String str) 追加字符串 sb.append("Hello")
insert(int offset, String str) 在指定位置插入字符串 sb.insert(5, "World")
replace(int start, int end, String str) 替换指定范围的内容 sb.replace(0, 5, "Hi")
delete(int start, int end) 删除指定范围内的字符 sb.delete(2, 5)
reverse() 反转字符串 sb.reverse()
capacity() 返回当前容量 sb.capacity()
setLength(int newLength) 设置字符串长度 sb.setLength(10)

6. 总结

类别 特点 适用场景
String 不可变,每次修改都会创建新对象 适用于少量字符串拼接字符串内容不变的情况
StringBuffer 可变线程安全(synchronized) 适用于多线程环境下的字符串拼接
StringBuilder 可变非线程安全性能最高 适用于单线程环境下的高效字符串拼接

7. 面试常问问题

Q1:String 为什么是不可变的?

  • String 内部使用 final char[] 存储,任何修改都会生成新的对象,保证了线程安全字符串常量池优化

Q2:为什么 StringBuilder 比 StringBuffer 性能更高?

  • StringBuffer 采用**synchronized 关键字**保证线程安全,而 StringBuilder 没有同步机制,因此性能更高。

Q3:什么时候使用 StringBuffer 而不是 StringBuilder?

  • 多线程环境需要安全地修改字符串时,使用 StringBuffer

**最终建议 **

  • 小规模拼接字符串String
  • 单线程拼接大量字符串StringBuilder
  • 多线程拼接大量字符串StringBuffer

你可能感兴趣的:(String、 StringBuffer 和 StringBuilder 的区别和作用及使用场景)