上一篇博客讲到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. strtok函数

    strtok函数是cstring文件里的函数 strtok函数是cstring文件里的函数 其功能是截断字符串 原型为:char *strtok(char s[],const char *delin) ...

  2. bzoj1560: [JSOI2009]火星藏宝图

    考虑到一个性质,A到B的距离一定不小于A到C再到B的距离,因为能够到达这三个点不可能构成锐角三角形 对于当前点的更新只需要找那些无法经过其它点再到当前点的点,相当于是一个y坐标单调减的上凸包,随便维护 ...

  3. YTU 2837: 编程题B-狐狸算卦

    2837: 编程题B-狐狸算卦 时间限制: 1 Sec  内存限制: 128 MB 提交: 76  解决: 52 题目描述 注:本题只需要提交需要完善部分的代码,请按照C++方式提交. 小熊和狐狸是邻 ...

  4. 《Image Generation with PixelCNN Decoders》论文笔记

    论文背景:Google Deepmind团队于2016发表在NIPS上的文章 motivation:提出新的image generation model based on pixelCNN[1]架构. ...

  5. java.lang.NoSuchMethodError: org.springframework.web.context.ConfigurableWebApplicationContext.setId

    运行spring报了这个错误,网上说是spring版本冲突,检查maven依赖,发现我依赖的是spring-core.3.0.5,但是spring-orm和spring-tx依赖了spring-bea ...

  6. 【183】VMware + CentOS 安装教程等

    目录: VMware 虚拟机安装 虚拟机上安装 CentOS VMware Tools 安装 为程序增加环境变量 其他 1. VMware 虚拟机安装   ※ 参考:VMware 虚拟机安装使用教程( ...

  7. 微型ORM:PetaPoco 学习资料整理

    github地址:https://github.com/CollaboratingPlatypus/PetaPoco petapoco 实体中字段去掉关联(类似于EF中的NotMap) 微型ORM:P ...

  8. E20170524-gg

    Awesome   adj. 可怕的; 令人敬畏的; 使人畏惧的; 极好的;

  9. bzoj 2151: 种树【贪心+堆】

    和数据备份差不多 设二元组(i,a[i]),开一个大根堆把二元组塞进去,以len排序,每次取出一个二元组 因为单纯的贪心是不行的,所以设计一个"反悔"操作. 记录二元组的前驱pr后 ...

  10. 51nod 1239 欧拉函数之和【欧拉函数+杜教筛】

    和bzoj 3944比较像,但是时间卡的更死 设\( f(n)=\sum_{d|n}\phi(d) g(n)=\sum_{i=1}^{n}f(i) s(n)=\sum_{i=1}^{n}\phi(i) ...