JDK常用类解读--StringBuffer、StringBuilder
上一篇博客讲到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的更多相关文章
- JDK常用类解读--String
一.字符串的不变性: 文章使用的源码是jdk1.8的.(下同) 1.首先可以看到`String`是`final`类,说明该类不可继承,保证不会被子类改变语义 2.String的值实际上就是一个字符数组 ...
- JAVA基础--常用类 String,StringBuffer, 基础数据类型包装类, Math类, Enum类
字符串相关类: String, StringBuffer String类为不可变的字符序列 String s1="hello"; String s2="hello&quo ...
- java 数据结构(二):java常用类 二 StringBuffer、StringBuilder
1.String.StringBuffer.StringBuilder三者的对比String:不可变的字符序列:底层使用char[]存储StringBuffer:可变的字符序列:线程安全的,效率低:底 ...
- 【Java常用类】StringBuffer、StringBuilder
Stringbuffer.StringBuilder String.StringBuffer.StringBuilder三者的异同? String:不可变的字符序列:底层使用char[]存储 Stri ...
- java 面向对象编程 --第十二章 JDK常用类
1. 系统类 java.lang包 System类 sys.out;sys.exit;sys.gc; sys.currentTimeMillis();----得到从1970-01-01到当前时间 ...
- Java基础(四):Java Number & Math 类、Character 类、String 类、StringBuffer & StringBuilder 类
一.Java Number & Math 类: 1.Number类: 一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double 等.然而,在实际开发 ...
- Java常用类之StringBuffer
StringBuffer 类: 1. java.lang.StringBuffer 代表可变的字符序列: 2. StringBuffer 和 String 类似,但是 StringBuffer 可以对 ...
- Java——常用类(StringBuffer)
[StringBuffer] <1>java.lang.StringBuffer代表可变的字符序列. <2>StringBuffer和String类似,但是StringBu ...
- JDK常用类_util
集合 Collection:集合顶层接口 AbstractCollection:集合抽象类 关联数组 Map:顶层接口 AbstractMap:抽象类实现,提供了子类的通用操作 HashMap:哈希表 ...
随机推荐
- jpa删除根据对象删除失败,报Removing a detached instance 错
引用:https://blog.csdn.net/zhanggnol/article/details/6307936 常用数据库表的删除办法,一般都会在DAO类中提供delete.如下例: publi ...
- 抓包工具Fiddler使用宝典之捕获手机报文
Fiddler 是通过代理来实现数据捕获的.对 Android 手机来说,也是通过将网络连接的代理指向 PC 机的 Fiddler port.来实现数据包的拦截. 以下,我以我的一次实践为例,向大家介 ...
- MySQL 存储过程传參之in, out, inout 參数使用方法
存储过程传參:存储过程的括号中.能够声明參数. 语法是 create procedure p([in/out/inout] 參数名 參数类型 ..) in :给參数传入值,定义的參数就得到了值 ou ...
- js常用操作事件
触发描述 方法 用法 点击 onclick="method();" 变换 onchange="testChange();" 双击 ondblclick= ...
- Linux __setup解析【转】
本文转载自:http://blog.csdn.net/fdaopeng/article/details/7895037 __setup这条宏在Linux Kernel中使用最多的地方就是定义处理Ker ...
- Android4.4.2系统添加自定义按键【转】
本文转载自:http://developer.t-firefly.com/thread-251-1-1.html 网上存在一些关于Android系统添加自定义按键的文章,但大多针对Android2.3 ...
- bzoj4594: [Shoi2015]零件组装机
论静态查错的重要性...乱搞题真难调 首先这题看起来就是要分治检验了. 考虑对于区间[l,r],分成[l,p-1]和[p,r]使得这两个区间合并可以得到[l,r],并且要保证后面一个区间较大 设前一个 ...
- 风云流水 jQuery技巧总结 (转)
jQuery技巧总结 (转) 一.简介 1.1.概述 随着WEB2.0及ajax思想在互联网上的快速发展传播,陆续出现了一些优秀的Js框架,其中比较著名的有Prototype.YUI.jQuery.m ...
- 在Main Thread中使用异步
Whenever you first start an Android application, a thread called "main" is automatically c ...
- Windbg脚本和扩展工具开篇
好长一段时间没写文章了,最近一直忙于为项目的可调式性做一些脚本和扩展工具,鉴于对windbg强大威力的震撼,以及相对较少的资料,笔者决定写一系列关于如何开发Windbg脚本和扩展命令的文章,您的支持是 ...