深入谈一谈String,StringBuilder,StringBuffer

本文详细解析了String、StringBuffer与StringBuilder的区别,重点介绍了它们在效率与线程安全性方面的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说来惭愧,上次面试某公司被问到 String 、StringBuilder 、StringBuffer 的区别,竟有些忘记了。

只是大概记得String 是不可变的,每次进行字符串的修改实际上是创建了 一个新的对象因此String的效率比较低;

StringBuffer 功能跟String类似,但是它的字符串是可以进行更改的,而且是线程安全的;StringBuilder 则是

StringBuffer的非线程安全版。当时面试官问到StringBuffer是如何实现线程安全的,自己不太确定于是很没有底气的

跟面试官说StringBuffer里面用到了synchronized 关键字,使得对StringBuffer对象的操作是线程安全的。一知半解,

没能深入理解其原理真是坑了自己!


今天仔细看了源码深入理解一番,写下来告诫自己,求知一定到知其然而又能知其所以然!

先看String的部分源码:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence

可以看到 String 用final修饰,表明了该类是不可继承的,继承了Serializable接口(可序列化),Comparable接口(比较和),CharSequence接口(字符串相关),源码注释中也有提到,当对象被创建后是不可变的:

* The {@code String} class represents character strings. All
 * string literals in Java programs, such as {@code "abc"}, are
 * implemented as instances of this class.
 * <p>
 * Strings are constant; their values cannot be changed after they
 * are created. String buffers support mutable strings.
 * Because String objects are immutable they can be shared. For example:
 * <blockquote><pre>
 *     String str = "abc";
 * </pre></blockquote><p>
 * is equivalent to:
 * <blockquote><pre>
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 * </pre></blockquote><p>
 * Here are some more examples of how strings can be used:
 * <blockquote><pre>
 *     System.out.println("abc");
 *     String cde = "cde";
 *     System.out.println("abc" + cde);
 *     String c = "abc".substring(2,3);
 *     String d = cde.substring(1, 2);
 * </pre></blockquote>
 * <p>

再来看StringBuffer :

 public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence

可以看到它跟String类的不同处在于没有实现Comparable接口,但是继承了 一个抽象类 AbstractStringBuilder ,我们接着看这个抽象类类:

/**
 * A mutable sequence of characters.
 * <p>
 * Implements a modifiable string. At any point in time it contains some
 * particular sequence of characters, but the length and content of the
 * sequence can be changed through certain method calls.
 *
 * <p>Unless otherwise noted, passing a {@code null} argument to a constructor
 * or method in this class will cause a {@link NullPointerException} to be
 * thrown.
 *
 * @author      Michael McCloskey
 * @author      Martin Buchholz
 * @author      Ulf Zibis
 * @since       1.5
 */
abstract class AbstractStringBuilder implements Appendable, CharSequence {//
//后续省略}


可以看到,该抽象类可以通过其定义的方法改变长度和内容(具体实现部分就不说了有兴趣可以自己看源码)。

再回来看StringBuffer,因为继承了 AbstractStringBuilder  所以它也具备了改变对象长度和内容的方法,继续看StringBuffer 的注释(只截取部分):

 * A thread-safe, mutable sequence of characters.
 * A string buffer is like a {@link String}, but can be modified. At any
 * point in time it contains some particular sequence of characters, but
 * the length and content of the sequence can be changed through certain
 * method calls.
 * <p>
 * String buffers are safe for use by multiple threads. The methods
 * are synchronized where necessary so that all the operations on any
 * particular instance behave as if they occur in some serial order
 * that is consistent with the order of the method calls made by each of
 * the individual threads involved.
 * <p>

注释的开头就提到,它是一个线程安全带的类,用synchronized关键字修饰可以修改对象长度或内容的方法,从而使其是线程安全的,能够拥有多线程的环境。append 方法:

    @Override
    synchronized StringBuffer append(AbstractStringBuilder asb) {
        toStringCache = null;
        super.append(asb);
        return this;
    }


可以看到它用synchronized修饰,然后调用父类的方法,实现线程安全的修改字符串。

其他方法类似上面的append方法,用synchronized修饰。用synchronized带来的问题也是显而易见的那就是效率问题,每次调用synchronize修饰的方法时就要获得对象锁,其他线程暂时无法获得该对象的读写权限严重影响效率。


最后看 StringBuilder :

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

跟 StringBuffer一样,再看注释:

* A mutable sequence of characters.  This class provides an API compatible
 * with {@code StringBuffer}, but with no guarantee of synchronization.
 * This class is designed for use as a drop-in replacement for
 * {@code StringBuffer} in places where the string buffer was being
 * used by a single thread (as is generally the case).   Where possible,
 * it is recommended that this class be used in preference to
 * {@code StringBuffer} as it will be faster under most implementations.
 *
 * <p>The principal operations on a {@code StringBuilder} are the
 * {@code append} and {@code insert} methods, which are
 * overloaded so as to accept data of any type. Each effectively
 * converts a given datum to a string and then appends or inserts the
 * characters of that string to the string builder. The
 * {@code append} method always adds these characters at the end
 * of the builder; the {@code insert} method adds the characters at
 * a specified point.
 * <p>

它与StringBuffer的最大差别是没用使用synchronized关键字修饰方法,所以它不是线程安全的,可以看一下的它的append方法:

    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

直接调用父类的append方法然后返回对象。所以它是非线程安全的,但是它的优点也很明显就是效率高。


最后的简单总结就是:效率 StringBuilder > StringBuffer > String 

线程安全:只有 StringBuffer ,原理是其方法使用synchronized关键字修饰。

最后还是希望自己多看源码,看源码才能更好的学习到其原理。 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值