String、StringBuffer、StringBuilder 三个的区别


在Java中 StringStringBufferStringBuilder都是用于处理字符串的类,它们在 性能、线程安全性、不可变性等方面都有明显的区别

一、String类

String是java中表示字符串的类,有两种定义的方式:
(1).引用类型常用的方法,用new方法创建。

String str = new String();

(2).用直接赋值的方式提供(从字符串常量池里面查找,并且返回地址)

String str = "";

String定义的字符串是不可变的,一旦String对象被定义之后,是不可改变的,每一次修改的时候,都会创建一个新的字符串对象

String的特点

1.不可变性:只要是创建之后,就不可以被修改,如果被修改,则是创建的一个新的字符串。
2.性能差:因为字符串不可变,每一次的修改都会重新创建,会导致性能相比于StringBuilder和StringBuffer低很多。
3.多线性安全:因为String不可变,因此多线程安全。

String示例

下面是验证String类不可变的示例,通过先查看str的内存地址,然后进行拼接操作,再查看str的内存地址,并且进行比较。

public class StingDemo {
    public static void main(String[] args) {
        String str = "he";
        String str1 = "0";
        System.out.println(System.identityHashCode(str));
        str = str+str1;
        System.out.println(System.identityHashCode(str));

    }
}

在这里插入图片描述
通过上面的运行结果,可以看出来,只要是字符串发生改变之后,都会创建一个新的对象,即字符串不可变

二、StringBuffer类

StringBuffer是一个可变的字符串序列,用它可以实现修改字符串内容。StringBuffer是多线程安全情况下修改字符串

StringBuffer的特点

(1)可以修改:可以改变对象的内容,但不会重新创建对象。
(2) 线程安全:StringBuffer方法是同步的,适用于多线程安全。
(3)性能相比于StringBuilder差相比于String好很多:由于线程同步的开销,StringBuffer 在单线程环境下的性能不如 StringBuilder。

StringBuffer示例

下面的StringBuffer构建了一个对象,并且调用其中的方法进行修改字符串的操作,由于是调用对象中的方法,因此是可变的。

public class StingDemo {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("a");
        sb.insert(1,"b");
        sb.append("cde");
        System.out.println(sb.toString());
        sb.reverse();
        System.out.println(sb.toString());
    }
}

在这里插入图片描述

三、StringBuilder类

StringBuilder 类与 StringBuffer 类唯一的区别是 StringBuilder 不是线程安全的,因此在单线程环境中,StringBuilder 的性能要比 StringBuffer 更高。StringBuilder 在多线程环境下不适用。

StringBuilder的特点

(1)可以修改:可以改变对象的内容,但不会重新创建对象。
(2) 非多线程安全:不适用于多线程环境。
(3)性能最优:由于没有线程同步的开销,StringBuilder在单线程环境表现好。

StringBuilder示例

下面的StringBuilder构建了一个对象,并且调用其中的方法进行修改字符串的操作,由于是调用对象中的方法,因此是可变的。


public class StingDemo {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        sb.append("a");
        sb.insert(1,"b");
        sb.append("cde");
        sb.append("asfdasf");
        System.out.println(sb.toString());
        sb.reverse();
        System.out.println(sb.toString());
    }
}

在这里插入图片描述

四、StringBuilder、StringBuffer、String的性能区别

(1)String:每次修改字符串时,都会创建新的对象,因此效率低下,尤其是在循环中大量拼接字符串时,性能会大幅下降。
(2)StringBuffer:提供了线程安全的字符串操作,性能要低于 StringBuilder。
(3)StringBuilder:适用于单线程环境,性能最好。

public class StingDemo {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        StringBuffer sbf = new StringBuffer();
        String str = "";
//        String
        long time1 =System.currentTimeMillis();
        for(int i = 0;i<100000;i++){
            str+=i;
        }
        long time2 = System.currentTimeMillis();
        System.out.println("String:"+(time2-time1));
//     StringBUffer
        long time4 =System.currentTimeMillis();
        for(int i = 0;i<100000;i++){
            sbf.append(i);
        }
        long time3 = System.currentTimeMillis();
        System.out.println("StringBuffer:"+(time3-time4));
//     StringBUilder
        long time5 =System.currentTimeMillis();
        for(int i = 0;i<100000;i++){
            sb.append(i);
        }
        long time6 = System.currentTimeMillis();
        System.out.println("StringBuffer:"+(time6-time5));

    }
}

在这里插入图片描述

通过上述的代码可以看出,当进行大量拼接操作的时候,StringBuffer和StringBuilder的性能比String强很多。

<think>嗯,用户之前问过关于String类能否被继承的问题,现在又接着问StringStringBufferStringBuilder区别。看来他们可能是在学习Java字符串处理相关的知识,或者是在准备面试题。我需要详细分析这三个类的区别,确保回答全面且易懂。 首先,要明确这三个类的用途和设计目的。String是不可变的,而StringBufferStringBuilder是可变的。但用户可能需要知道为什么会有这样的设计,以及在实际应用中如何选择。 然后,线程安全是一个重点。StringBuffer是线程安全的,因为它的方法都是同步的,而StringBuilder不是。需要解释清楚线程安全的概念,以及在不同场景下的影响。 性能比较也很重要。通常StringBuilder在单线程下更快,但为什么?需要提到同步带来的开销,以及字符串操作的频繁程度如何影响性能。 接下来,可能需要举例说明它们的用法差异。比如字符串拼接时,使用String会生成多个对象,而使用StringBuilderStringBuffer可以避免这种情况,提高效率。 用户可能还会关心什么时候应该用哪个类。比如在单线程环境下推荐使用StringBuilder,多线程则用StringBuffer,而String适用于不需要修改字符串内容的情况。 此外,需要提到JVM对String的优化,比如字符串常量池,以及如何通过final关键字保证不可变性。还有,StringBufferStringBuilder的API几乎相同,但同步处理不同。 要避免过于技术化的术语,用简单易懂的语言解释。可能还要对比它们的继承结构,比如都继承自AbstractStringBuilder,但String是独立的。 最后,总结三者区别,强调线程安全、可变性和性能,并给出使用建议。这样用户能有一个清晰的比较,方便记忆和应用。</think>--- ### 🚩 核心区别总结 | 特性 | `String` | `StringBuffer` | `StringBuilder` | |--------------------|---------------------------|---------------------------|---------------------------| | **可变性** | 不可变 | 可变 | 可变 | | **线程安全** | 天然安全(不可变) | 安全(同步方法) | 不安全(无同步) | | **性能** | 高频修改性能差 | 线程安全但较慢 | 单线程下最快 | | **内存开销** | 易产生大量中间对象 | 对象复用 | 对象复用 | | **适用场景** | 常量字符串/少量操作 | 多线程字符串操作 | 单线程字符串操作 | --- ### 1️⃣ **不可变的 `String`** ```java String str = "Hello"; str += " World"; // 实际生成新对象:效率低下 ``` #### 核心特点: - **不可变性**:每次操作都生成新对象(适合缓存、哈希键等场景) - **字符串常量池优化**:相同字面量复用对象(`"a" + "b"` 编译期优化为 `"ab"`) - **线程安全**:无需额外同步(天然线程安全) #### 典型使用场景: - 配置文件读取 - HTTP 请求参数 - 数据库连接字符串等**不需要修改**的场景 --- ### 2️⃣ **线程安全的 `StringBuffer`** ```java StringBuffer sb = new StringBuffer(); sb.append("Hello").append(" World"); // 直接修改原对象 ``` #### 核心特点: - **同步方法**:所有关键方法用 `synchronized` 修饰(线程安全但性能较低) - **初始容量 16**:自动扩容(每次扩容 `旧容量*2 + 2`) - **方法链调用**:支持链式写法(`append().insert().delete()`) #### 典型使用场景: - 多线程环境下的日志拼接 - 并发服务器中的请求处理 - **JDK 1.0** 开始存在(早期方案) --- ### 3️⃣ **高性能的 `StringBuilder`** ```java StringBuilder sb = new StringBuilder(); sb.append("Java").reverse(); // 直接修改原对象 ``` #### 核心特点: - **无同步开销**:方法未加锁(单线程性能比 `StringBuffer` 高约 **10-15%**) - **初始容量 16**:扩容逻辑 `StringBuffer` 相同 - **JDK 1.5+** 引入:为单线程场景优化 #### 典型使用场景: - 单线程下的 JSON/XML 构建 - 循环体内的字符串处理 - 高频字符串操作(如大数据处理) --- ### ⚡️ 性能对比测试 ```java // 测试代码片段 public void testPerformance() { int N = 100000; // String 测试 long start = System.currentTimeMillis(); String s = ""; for (int i = 0; i < N; i++) { s += i; // 每次循环创建新对象 } System.out.println("String: " + (System.currentTimeMillis() - start) + "ms"); // StringBuffer 测试 start = System.currentTimeMillis(); StringBuffer sb1 = new StringBuffer(); for (int i = 0; i < N; i++) { sb1.append(i); } System.out.println("StringBuffer: " + (System.currentTimeMillis() - start) + "ms"); // StringBuilder 测试 start = System.currentTimeMillis(); StringBuilder sb2 = new StringBuilder(); for (int i = 0; i < N; i++) { sb2.append(i); } System.out.println("StringBuilder: " + (System.currentTimeMillis() - start) + "ms"); } ``` #### 典型结果(10万次循环): - `String`: 约 **5000ms**(产生大量垃圾对象) - `StringBuffer`: 约 **10ms** - `StringBuilder`: 约 **5ms** --- ### 🛠️ 选型建议 1. **优先用 `String`** - 数据不经常变化 - 需要作为常量使用(如 `Map` 的键) 2. **多线程操作 → `StringBuffer`** - 多线程日志处理 - 并发环境下的字符串组装 3. **单线程操作 → `StringBuilder`** - 循环体内字符串操作 - SQL 语句拼接 - 高频字符串处理 --- ### 📌 底层实现揭秘 #### 共有特性(`StringBuffer`/`StringBuilder`): ```java // AbstractStringBuilder 中的核心存储 char[] value; // 动态数组存储字符 int count; // 实际字符数量 ``` #### 扩容机制: 1. 计算新容量 = `原容量*2 + 2` 2. 如果仍不足,直接扩容到**目标长度** 3. 调用 `Arrays.copyOf()` 复制数据 --- ### ❌ 常见误区 1. **错误认知**:`StringBuilder` 在所有场景都比 `StringBuffer` 快 **真相**:在单线程下更快,但在多线程中频繁同步时可能更慢 2. **错误写法**:在循环中用 `+` 拼接字符串 **修正**:应使用 `StringBuilder`(编译器不会优化循环内的 `+` 操作) 3. **过度优化**:预设容量(仅在超大数据处理时有意义) ```java // 合理预设容量(减少扩容次数) StringBuilder sb = new StringBuilder(1024); ``` --- **总结**:理解三者的差异是写出高效 Java 代码的基础,根据线程安全和性能需求做出精准选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值