从底层原理来分析,String构建的字符串对象,其内容理论上是不能被改变的。一旦定义了String对象就无法再改变其内容,但很多时候我们还是需要改变字符串的内容的,所以String类就存在一定的短板。
另外从应用层面来分析,String字符串的执行效率其实是比较低的。举个例子,就比如常见的字符串拼接,很多人喜欢使用“+号”来拼接String字符串。其实如果是操作少量的字符串,使用String还凑活,一旦同时操作的字符串过多,String的效率就极低了。之前曾做过一个关于10万个字符串拼接的实验。同等条件下,利用“+”号进行拼接所需要的时间是29382毫秒,利用StringBuffer所需要的时间只有4毫秒,而StringBuilder所用的时间更是只需2毫秒,这效率真是天差地别!
我们还可以通过下面这个稍微简单点的案例,来看看Java底层是如何处理字符串拼接的。
String str = "Hello" + "World";
System.out.println("str=" + str);
相信很多朋友都会用 “+”号 来进行字符串拼接,因为觉得该方式简单方便,毕竟 一 “+” 了事。
那么利用 “+”号来拼接字符串是最好的方案吗?
肯定不是的!如果我们使用JAD反编译工具对上述Java字节码进行反编译,你会发现不一样的结果,上述案例反编译后得到的JAD文件内容如下所示:
import java.io.PrintStream;
public class StringTest13
{
public StringTest13()
{
}
public static void main(String args[])
{
String s = "HelloWorld";
System.out.println((new StringBuilder()).append("str=").append(s).toString());
}
}
从反编译出来的JAD文件中我们可以看出,Java在编译的时候会把 “+”号操作符替换成StringBuilder的append()方法。也就是说,“+”号操作符在拼接字符串的时候只是一种形式,让开发者使用起来比较简便,代码看起来比较简洁,但底层使用的还是StringBuilder操作。
既然 “+”号 的底层还是利用StringBuilder的append()方法操作,那么我们为什么不直接使用StringBuilder呢?你说对吧?而且当我们需要操作大量的字符串时,更不推荐使用String,比如:
String str = "";
for (int i = 0; i < 10000; i++) {
str = str + "," + i;
}
上面这段代码,虽然可以实现字符串的拼接,但是在该循环中,每次循环都会创建一个新的字符串对象,然后扔掉旧的字符串。如果是10000次循环,就会执行10000次这样的操作。而这些操作中的绝大部分字符串对象都是临时对象,最终都会被扔掉不用,这就会严重地浪费内存,并会严重影响GC垃圾回收的效率。
为了能提高拼接字符串的效率,Java给我们提供了StringBuffer和StringBuilder,它们都是可变对象,可以预分配缓冲区。当我们往StringBuffer或StringBuilder中新增字符时,不会创建新的临时对象,可以极大地节省了内存。可以说,好处多多。
那么接下来我们就一起学习 StringBuffer、StringBuilder 的用法吧。
二. StringBuffer
1. 简介
StringBuffer
是一种可变的字符串类,即在创建StringBuffer
对象后,我们还可以随意修改字符串的内容。每个StringBuffer
的类对象都能够存储指定容量的字符串,如果字符串的长度超过了StringBuffer
对象的容量空间,则该对象的容量会自动扩大。
另外我们在使用StringBuffer类时,比如每次调用toString()方法,都会直接使用缓存区的toStringCache 值来构造一个字符串,这每次都是对StringBuffer对象本身进行操作,而不会重新生成一个新对象。所以如果我们需要对大量字符串的内容进行修改,推荐大家使用StringBuffer。