上一篇博客讲到String对象一旦被创建该内容就不能被修改了如:

        String s = "hello world";
s.substring(6);
s.replace("hello","hi");
String s1 = s+"java";
System.out.println(s);//结果:hello world String中的方法只是返回新的字符串,并不改变原来的String对象
System.out.println(s==s1);//结果:false 字符串拼接也只是创建了一个新的对象而已

  实际上String对象之所以不能被修改其本质因为String对象存储值的成员变量char value[] 无法被修改,如果希望多次修改String或者进行多次字符串拼接特别是在循环体中时,为了防止过多的创建和销毁对象,可以使用到 StringBuffer、StringBuilder;其实是先使用char[],然后可以对这个字符数组进行各种修改操作,最终new一个String对象并且将之前修改好的char[]的值作为String的value。

  StringBuffer、StringBuilder都继承了AbstractStringBuilder抽象类:

abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;//没有使用final private修饰,说明该引用可以指向其他char[]对象,同时也是可以被子类访问到的 /**
* The count is the number of characters used.
*/
int count;

接下来看看最常用的append方法,StringBuffer、StringBuilder虽然重写该方法,最终也还是调用的父类append:

//AbstractStringBuilder
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);//检查value数组是否需要扩容,需要的话进行扩容
str.getChars(0, len, value, count);//备份String对象中的char[]值到value中
count += len;
return this;
}
//StringBuilder
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
//StringBuffer
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}

  StringBuffer、StringBuilder类的代码实现上基本一致,但是StringBuffer中的所有公开的方法有synchronized修饰,说明StringBuffer是可以保证线程安全的,当然StringBuilder没有加锁,效率自然更高,所以在多数情况下不需要考虑线程安全问题时应该使用StringBuilder。

再来来看看StringBuffer、StringBuilder的toString方法:

//StringBuilder
@Override
public String toString() {
// Create a copy, don't share the array 创建副本,不共享数组
return new String(value, 0, count);
} //StringBuffer
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}

  可以发现StringBuilder、StringBuffer的toString最后创建String对象使用的构造器不同,前者使用的构造器是将StringBuilder的char[] 重新创建一个副本作为String的值;后者是先创建副本,并使用toStringCache变量将副本缓存,然后调用String构造器直接将toStringCache引用的char[]与String共享,不需要在进行数组拷贝,算是一种优化,toStringCache同样是被private修饰并且不可修改,当调用StringBuffer其他的修改char[]方法(如append)时,toStringCache会被重新置为null。

   这里有个问题,为什么StringBuilder toString中char[]不能做缓存并与String共享,应该是因为StringBuffer是同步的,在调用toString()方法的时候,它的value数组不会被修改,而StringBuilder它没有同步,在调用toString()时无法保证成员变量不被修改(如果使用缓存,在创建对象String的同时,有可能该缓存会被其他线程清空),所以需要重新创建一个char[],尽量保证如果其他线程改变了这个char[],不会影响到结果String的生成。

 

JDK常用类解读--StringBuffer、StringBuilder的更多相关文章

  1. JDK常用类解读--String

    一.字符串的不变性: 文章使用的源码是jdk1.8的.(下同) 1.首先可以看到`String`是`final`类,说明该类不可继承,保证不会被子类改变语义 2.String的值实际上就是一个字符数组 ...

  2. JAVA基础--常用类 String,StringBuffer, 基础数据类型包装类, Math类, Enum类

    字符串相关类: String, StringBuffer String类为不可变的字符序列 String s1="hello"; String s2="hello&quo ...

  3. java 数据结构(二):java常用类 二 StringBuffer、StringBuilder

    1.String.StringBuffer.StringBuilder三者的对比String:不可变的字符序列:底层使用char[]存储StringBuffer:可变的字符序列:线程安全的,效率低:底 ...

  4. 【Java常用类】StringBuffer、StringBuilder

    Stringbuffer.StringBuilder String.StringBuffer.StringBuilder三者的异同? String:不可变的字符序列:底层使用char[]存储 Stri ...

  5. java 面向对象编程 --第十二章 JDK常用类

    1.  系统类 java.lang包   System类 sys.out;sys.exit;sys.gc; sys.currentTimeMillis();----得到从1970-01-01到当前时间 ...

  6. Java基础(四):Java Number & Math 类、Character 类、String 类、StringBuffer & StringBuilder 类

    一.Java Number & Math 类: 1.Number类: 一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double 等.然而,在实际开发 ...

  7. Java常用类之StringBuffer

    StringBuffer 类: 1. java.lang.StringBuffer 代表可变的字符序列: 2. StringBuffer 和 String 类似,但是 StringBuffer 可以对 ...

  8. Java——常用类(StringBuffer)

    [StringBuffer]   <1>java.lang.StringBuffer代表可变的字符序列. <2>StringBuffer和String类似,但是StringBu ...

  9. JDK常用类_util

    集合 Collection:集合顶层接口 AbstractCollection:集合抽象类 关联数组 Map:顶层接口 AbstractMap:抽象类实现,提供了子类的通用操作 HashMap:哈希表 ...

随机推荐

  1. Python常用的几种常用的内置函数

    abs(x)              用于返回绝对值 divmod(x,y)       函数中传入两个数字,返回的是x/y的一个结果的元组(商,余数) pow(x,y)            用于 ...

  2. Linux Grub系统加密、破密、修复

    一.在重新启动系统时候按任意键进入 grub界面  Grub加密 一.title前的密码 修改grub.conf 这种加密只是在用户要进入grub界面的时候提示要输入密码,但是可以正常进入系统,有没有 ...

  3. URL编码总结

    URL编码总结           URL是Universal Resource Locator的简称.翻译过来那就是统一资源定位符,好吧,我们常常会俗称为网页地址. 一个URL的格式一般是这种:协议 ...

  4. 深刻理解Java中形參与实參,引用与对象的关系

    声明:本博客为原创博客,未经同意.不得转载! 原文链接为http://blog.csdn.net/bettarwang/article/details/30989755 我们都知道.在Java中,除了 ...

  5. [转] 买彩票的利器--gun

    源链接 还在自己买彩票吗,有个现成的:GNU shuf命令. shuf -i - -n | 这样就会产生两组彩票(1~36个数字任选) 当然还可以派其他用途,比如: shuf -e clubs hea ...

  6. encodeURIComponent

    <script type="text/javascript"> function show(){ var f="#wer中文测试"; f = enc ...

  7. ios archives 出现的是other items而不是iOS Apps的解决方案

    ios archives 出现的是other items而不是iOS Apps的解决方案 项目打包时出现的是不是出现在iOS Apps栏目下面,而是Other Items而且右边对应的Upload t ...

  8. js实现replaceAll功能

    js中没有原生的replaceAll 方法. function replaceAll(str , replaceKey , replaceVal){ var reg = new RegExp(repl ...

  9. 定时邮件 已经稳定运行10天+ 从局域网linux到外网邮箱

  10. 暴走吧!Snapdragon SDK开发速成指南

    (文/Aurora J) Qualcomm的Snapdragon处理器.它快如闪电.效率极高.擅长挑战多任务极限,而且拥有攻城狮们梦寐以求的无限潜能.它能确保您的手机集4G LTE.极速体验.长久续航 ...