String、StringBuilder、StringBuffer的区别

简介: String、StringBuilder、StringBuffer的区别

概述

String、StringBuilder和StringBuffer都是用来处理字符串的类,底层都是通过char[]数组实现的。(jdk1.8及之前)

String是不可变的(线程安全的),StringBuilder和StringBuffer是可变的。StringBuffer是线程安全的,而StringBuilder是非线程安全的。具体如下:

String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;

StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。

如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder。

下面我们从三个维度:可变性、线程安全性、性能来分析区别。

String为何不可变,StringBuilder和StringBuffer为何可变

String部分源码

 
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
 
    //。。。。。。。。。。。。。。。。。。
}

String类被声明为final,这意味着它不能被继承。那么他里面的方法就是没办法被覆盖的。

用final修饰字符串内容的char[] (从JDK 1.9开始,char[]变成了byte[]),由于该数组被声明为final,一旦数组被初始化,就不能再指向其他数组

String类没有提供用于修改字符串内容的公共方法。例如,没有提供用于追加、删除或修改字符的方法。如果需要对字符串进行修改,会创建一个新的String对象。所以说String是不可变的。

与String不同StringBuilder和StringBuffer底层封装的char[]并没有用final修饰,这意味着它是可以修改的。

StringBuilder部分源码

public final class StringBuilder
    extends AbstractStringBuilder
    implements Serializable, CharSequence
{
    //。。。。。。。。。。。。。。。。。
}
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;
 
    //。。。。。。。。。。。。。
}

StringBuffer部分源码

public final class StringBuffer
    extends AbstractStringBuilder
    implements Serializable, CharSequence
{
    //。。。。。。。。。。。。。。。。
}
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;
    //。。。。。。。。。。。。。。。。。。。。。。。
}

StringBuffer为何线程安全的,而StringBuilder为何非线程安全

StringBuffer是线程安全的,它的方法都使用了synchronized关键字进行同步。在每个方法内部,通过加锁(synchronized)来确保在多线程环境下的安全访问。这意味着当一个线程访问StringBuffer的方法时,其他线程需要等待锁释放后才能执行相应的方法。因此,StringBuffer适用于多线程环境下对字符串的修改操作。

    //StringBuffer部分源码
    @Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }
 
    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

而StringBuilder则没有使用synchronized关键字进行同步,它是非线程安全的。这样可以提高性能,因为不需要进行锁的获取和释放操作。但是,在多线程环境下,如果有多个线程同时访问和修改StringBuilder对象,可能会导致数据不一致或出现竞态条件的问题。因此,StringBuilder适用于单线程环境下对字符串的修改操作。

    
    //StringBuilder部分源码
    @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
 
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

三者性能分析

String:由于String是不可变的,每次对String进行修改操作时,都会创建一个新的String对象。这可能导致频繁的对象创建和垃圾回收,影响性能

StringBuilder:由于StringBuilder是可变的,它使用可变的字符数组存储字符串,不会每次都创建新的对象。在需要频繁进行字符串拼接、替换等操作时,使用StringBuilder可以提高性能

StringBuffer:与StringBuilder类似,StringBuffer也是可变的,但是它是线程安全的。在多线程环境下,由于同步机制的存在,StringBuffer的性能可能会稍低于StringBuilder

使用场景

String:适用于不需要频繁修改字符串内容的场景。由于String是不可变的,每次对String进行拼接、替换或者修改操作时,都会创建一个新的String对象,这样可能会导致频繁的对象创建和垃圾回收,影响性能。因此,如果字符串内容不需要改变,或者只需要读取字符串的值,可以使用String。

  1. 对于一些常量字符串或者字面量,例如日志输出时的提示信息、固定格式的输出等,由于它们的值是固定的,不需要做任何修改,因此可以使用String。
  2. 在某些业务逻辑中,需要对字符串进行一些操作,但这些操作的结果不会影响原始字符串。例如,从数据库中查询到的数据如果需要展示给用户,通常不会被修改,这种场景下可以使用String。

StringBuilder:适用于单线程环境下需要频繁修改字符串的场景。由于StringBuilder是可变的,它使用可变的字符数组存储字符串,不会每次都创建新的对象。因此,在需要频繁进行字符串拼接、替换等操作时,使用StringBuilder可以提高性能。

  1. 在开发Web应用时,需要将多个字符串拼接成一个完整的HTML页面,这种场景下可以使用StringBuilder。
  2. 当需要从文件中读取数据,并进行一系列复杂的字符串操作时,可以使用StringBuilder。

StringBuffer:适用于多线程环境下需要频繁修改字符串的场景。与StringBuilder类似,StringBuffer也是可变的,但是它是线程安全的,内部的方法都使用了synchronized关键字进行同步。这意味着在多线程环境下,多个线程可以安全地同时访问和修改StringBuffer对象。因此,如果在多线程环境下需要频繁进行字符串操作,应该使用StringBuffer来确保线程安全。

  1. Web服务器需要同时处理多个客户端请求,这种场景下可以使用StringBuffer来确保线程安全。
  2. 一个多线程的任务,需要将多个线程的执行结果拼接成一个完整的字符串,可以使用StringBuffer。
目录
相关文章
|
1月前
|
安全 Java
Java StringBuffer 和 StringBuilder 类
Java StringBuffer 和 StringBuilder 类
16 0
|
6天前
|
存储 编解码 算法
Java 的 String StringBuilder StringBuffer(上)
Java 的 String StringBuilder StringBuffer
24 0
|
20天前
|
移动开发 安全 Java
String、StringBuffer 、StringBuilder、StringJoiner
String、StringBuffer 、StringBuilder、StringJoiner
|
19天前
|
Java API 索引
Java基础—笔记—String篇
本文介绍了Java中的`String`类、包的管理和API文档的使用。包用于分类管理Java程序,同包下类无需导包,不同包需导入。使用API时,可按类名搜索、查看包、介绍、构造器和方法。方法命名能暗示其功能,注意参数和返回值。`String`创建有两种方式:双引号创建(常量池,共享)和构造器`new`(每次新建对象)。此外,列举了`String`的常用方法,如`length()`、`charAt()`、`equals()`、`substring()`等。
15 0
|
1月前
|
Java
【Java】如果一个集合中类型是String如何使用拉姆达表达式 进行Bigdecimal类型计算?
【Java】如果一个集合中类型是String如何使用拉姆达表达式 进行Bigdecimal类型计算?
25 0
|
1月前
|
Java
Java String split()方法详细教程
Java String split()方法详细教程
25 0
|
1月前
|
存储 缓存 安全
【Java】Java中String不可变性的底层实现
【Java】Java中String不可变性的底层实现
18 0
|
1月前
|
Java 索引
Java中String方法学习总结_kaic
Java中String方法学习总结_kaic
|
1天前
|
存储 安全 Java
聊聊Java中的常用类String
聊聊Java中的常用类String
5 0
|
4天前
|
存储 缓存 Java