幽兰生空谷
--绝世独自开

Java面试题分享-String、StringBuffer 和StringBuilder

String、StringBuffer 和StringBuilder

String、StringBuffer 和StringBuilder的区别,这个问题在Java初级面试中经常被问到,下面我们来了解一下它。

区别:

1.String 长度不可变,而 StringBuilder 和 StringBuffer 长度可变。

2.它们的执行速度不同:StringBuilder > StringBuffer > String

3.StringBuilder 线程不安全 和 StringBuffer 线程安全

原因1:

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[];
    // ......
    }

StringBuilder

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

StringBuffer

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

AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /** 该值用于字符存储。
     * The value is used for character storage.
     */
    char[] value;
    // .....   
}

分析:

从以上源码中我们可以看到,String 这个类底层使用了 final 修饰的长度不可变的字符数组,所以它长度不可变,

private final char value[];

而 StringBuilder 和 StringBuffer 都继承自 AbstractStringBuilder ,且AbstractStringBuilder 底层使用的是可变字符数组,所以二者长度不变。

原因2:

它们的执行速度不同:StringBuilder > StringBuffer > String

我们先看一下下面这段代码:

代码:

package com.itheibai.test;
public class StringTest {
    public static void main(String[] args) {
        String str = "abc";
        System.out.println("str 连接之前:" + str);
        System.out.println("str 哈希值:" + str.hashCode());
        str = str + "de";
        System.out.println("str 连接之后:" + str);
        System.out.println("str 哈希值:" + str.hashCode());
    }
}

执行结果:

分析:

整个程序执行完,从表面上看,似乎我们改变了 str 对象的字符串长度,与源码不符。但从 str 的哈希值来看,两次输出的哈希值并不相同,也就是说拼接后的字符串对象,和原来的字符串对象,并不是同一个对象。什么原因呢?

其实 JVM 是先创建了一个 str 对象,将 “abc”赋值给 str ,然后在内存中有创建了第二个 str 对象,将拼接后的字符串 “abcde”赋值给第二个 str 对象,此时 Java 虚拟机的垃圾回收机制开始工作,将第一个 str 对象回收。

所以,String类型的字符串要完成“改变长度”这样的操作,就需要不断地创建再回收,创建再回收,无形中经过了很多步骤,而 StringBuilder 和 StringBuffer 数组可变,直接可进行更改,所以要更快。

而 StringBuilder 为什么比 StringBuffer 要快呢?

先看一下源码:

源码:

StringBuilder

@Override
public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

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;
}

分析:

从源码中我们可以看出,StringBuffer 的 append 方法都被 synchronized 关键字修饰了(不止上面这些方法,源码中的所有方法都被 synchronized 修饰了),

synchronized 关键字是给线程加锁,加锁是会损耗性能的,所以 StringBuilder 要比 StringBuffer 快。

原因3:

StringBuilder 线程不安全 和 StringBuffer 线程安全

分析:

结合原因2的源码进行分析,StringBuffer 对象的所有方法都被 synchronized 关键字修饰,给线程加了锁,所以线程安全。继续往下看源码:

StringBuffer

@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

StringBuilder

@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

可以看出,StringBuffer 每次获取 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串,而 StringBuilder 是每次都需要复制一次字符数组,在构造一个字符串。

所以,缓冲区这也是对 StringBuffer 的一个优化吧,不过 StringBuffer 的这个 toString 方法仍然是同步的。

可以这样理解,如果一个 StringBuffer 对象的字符串在字符串缓冲区被多个线程同时使用时,也就是多线程同时操作,这样会有出现错误操作的概率,为了保证线程的安全性,进行加锁,这样会使同一时间只有一个线程获得权限,其他线程必须等待该线程结束并释放锁才能获得权限,这样线程非常安全,虽然效率慢了点,但是当项目安全性要求很高时就必须用 StringBuffer 。

单线程下还是用 StringBuilder 更快一些。

赞(3) 打赏
版权声明:本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
文章名称:《Java面试题分享-String、StringBuffer 和StringBuilder》
文章链接:https://www.itheibai.com/archives/772
免责声明:根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途,网站会员捐赠是您喜欢本站而产生的赞助支持行为,仅为维持服务器的开支与维护,全凭自愿无任何强求。

评论 抢沙发

评论前必须登录!

 

养成“打赏”的好习惯,从我做起!

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册