191213P1 StringBuffer和String的区别是什么

StringBuffer和String的区别是什么

作者:邵发
官网:http://afanihao.cn/java

StringBuffer 是一个用于构造字符串的工具类,是面试里常考的一个问题。

 

1 字符串的拼接

还得先从String说起。在Java里,构造一个字符串可以直接用String的拼接功能,简单而直观。
比如,

String s1 = "阿发";
s1 += "你好";
s1 += "Hello";
s1 += "World";

看起来很简单,是不是?

但这一段代码存在一定的迷惑性,一般初学者会觉得,这4行代码修改了String对象只有一个,就是s1对象。

其实不然,这里是创建了4个String对象。也就是说,

    s1 += "你好" ;

相当于:

    String str = s1 + "你好";
    s1 = str;

其中,s1 + "你好" 是创建一个新的String对象。

 

通过单步调试,观察s1引用的实例ID值,可以更清楚的认识上述结论。

此时,s1对象的实例ID为19。每一个Java实例,都有一个不同的ID。

继续运行,s1的实例ID为29,值变成了"阿发你好"。说明此时产生了一个新的String对象(id=29的实例)

继续运行,s1的实例ID为31,说明又创建了一个新的String对象。

最后,又创建了一个String对象,实例id=33,值为"阿发你好helloworld"

这个演示告诉我们,字符串拼接 s1 = s1 + "XXX" 之后,实际上是创建了新的String对象。一共创建了4个String对象,前3个由于失去了引用,将会被GC自动回收。

 

2 效率问题

一般认为,使用String进行字符串拼接存在效率问题。怎么会有效率问题呢?举一个例子。
比如,我们要求对一个字符串的$字符进行转义,在$字符前端添加一个\。

示例:
   原文 var a = ${name}
   转义后 var a = \${name}

用代码实现为:

public static String escape(String source)
{
    String result = "";
    for(int i=0; i<source.length(); i++)
    {
        char ch = source.charAt(i);
        if( ch == '$')
            result += '\\'; // 附加一个反斜杠
        result += ch;
    }
    return result;
}

public static void main(String[] args) throws Exception
{
    String source = "var a = ${name}";
    String result = escape(source);
    System.out.println(result);
}

根据在第1节中的阐述,在escape()中每执行一次  result += xxx 就是抛弃了原有result对象,创建了一个新的result对象。在这里,一共执行了16次拼接操作,所以一共创建并抛弃了16个String对象。

现在放大这个问题的规模,如果输入长度为1000的字符串进行处理,则至少创建并抛弃1000个String对象。这显然效率上有点问题,因为过于频繁的抛弃对象交给GC来处理,对GC也是一个负担啊。

 

3 StringBuffer

StringBuffer,是一个字符串的构造工具。可以认为它内部包含了一个字符数组,可以修改里面的字符的值。

例如,StringBuffer的基本用法示例:

// 创建一个初始容量为100的Buffer,如果实际内容超过容量则内部会自动扩展容量
StringBuffer sbuf = new StringBuffer(100);

// 往里面塞内容
sbuf.append("阿发");
sbuf.append("你好");
sbuf.append("Hello");
sbuf.append("World");

// 最终构造的字符串
String result = sbuf.toString();

其实一看到Buffer字样,我们应该明白它是什么意思。它是一个容器,一个缓冲区,可以存放字符。自然地,当使用append()往容器里塞东西的时候,并没有什么效率问题。

下面用StringBuffer来实现上述的转义功能。

public static String escape2(String source)
{
    StringBuffer sbuf = new StringBuffer(source.length()*2); // 最好预估一下容量
    for(int i=0; i<source.length(); i++)
    {
        char ch = source.charAt(i);
        if( ch == '$')
            sbuf.append('\\'); // 附加一个反斜杠
        sbuf.append(ch);
    }
    return sbuf.toString();
}

把一个一个字符塞到一个容器里,会有效率问题吗,当然没有。会创建1000个String对象吗,当然不会。这便是StringBuffer在处于字符串构造问题时的优势所在。

StringBuffer就像一个数组一样,其他用法可以自己百度一下。比如,StringBuffer可以修改某一个置的字符。sbuf.setCharAt(..) 。它的容量可以自动扩展,不过最好在初始化的时候就预估一个容量。

 

4 结论

当需要执行大量的字符拼接构造问题时,应考虑使用 StringBuffer 来实现,以优化执行效率。

当只进行少量拼接操作时,还是直接使用String吧,别大费周章创建StringBuffer了。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿发你好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值