StringBuilder做字符串拼接高效的原因

StringBuilder做字符串拼接高效的原因

1.与String相比

通过分析源码,发现两者底层都是用一个数组来存储字符

public final class String implements java.io.Serializable,Comparable<String>,CharSequence{/** The value is used for character storage */private final char value[];

这里需要注意,StringBuilder本身并没有定义value数组,我们需进入其父类AbstractStringBuilder中,可以发现用来存储字符的数组value.

/**
* The value is used for character storage
*/
char value[];

可以发现,String底层的数组是用final修饰的,是一个数组常量,而StringBuilder底层用来接收存储字符的数组是一个变量.所以前者在创建之后是没法更改,而后者可以

这里我们看一段代码

package reason;
public class Test {public static void main(String[] args){String str = "不变";System.out.println(str);str = "变了"System.out.println(str);}
}

在这里插入图片描述
结果却是str从最初的"不变",到后来的"变了",字符串str发生了改变,但String底层的数组不是常量吗?为什么值会发生改变?

其实在内存中String发生了这样的变化:
在这里插入图片描述
在内存中,我们先创建了一个str对象,并且赋值"不变",之后其实并不是在原有创建的str对象上作更改,而是又创建了一个新的字符串对象,并且赋值变了,把之前的引用类型变量str指向新创建的对象,而之前创建的对象处于等待被回收的状态,如果没有被调用,就会被JVM提供的垃圾回收机制给回收掉.

到这里我们可以发现,之所以String本身做字符串拼接执行速度慢,是因为其本质上是一个不断创建新对象,并且回收旧对象的过程.那说到StringBuilder和StringBuffer,它们创建的对象是变量,对变量操作就是对对象操作,中间不存在对象的创建和回收,所以速度比String快

那真的是这样吗?我们进入到StringBuilder封装后的源代码,查看其append方法

@Overridepublic StringBuilder append(String str) {super.append(str);return this;}

发现StringBuilder在使用append方法时,如果传进来的参数是String类型 的,会去调用其父类的append方法,也就是AbstractStringBuilder的append方法,我们进入AbstractStringBuilder

 public AbstractStringBuilder append(String str) {if (str == null)return appendNull();int len = str.length();ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}

发现当传入的字符串是null时,会去调用appendNull方法,找到appendNull方法的源码

 private AbstractStringBuilder appendNull() {int c = count;ensureCapacityInternal(c + 4);final char[] value = this.value;value[c++] = 'n';value[c++] = 'u';value[c++] = 'l';value[c++] = 'l';count = c;return this;}

这里需要注意,count是用来记录存储字符的数组的长度首先会用一个变量c存放当前数组的长度,再去调用ensureCapacityInternal方法来进行数组扩容.(等会append方法也会调用这个方法)我们先找到ensureCapacityInternal的源码,它和append,appendNull一样在AbstractStringBuilder类里

private void ensureCapacityInternal(int minimumCapacity) {// overflow-conscious codeif (minimumCapacity - value.length > 0) {value = Arrays.copyOf(value,newCapacity(minimumCapacity));}}

发现了这个方法其实就是再做数组的扩容,利用的是Arrays类里的copyOf进行数组的扩容

回到上面appendNull方法中,会将当前数组的长度加4作为参数传入ensureCapacityInternal方法,将value数组扩容四个大小,并且把最后四个值改为null,所以我们利用append方法拼接一个值为null的字符串,得到的也是null

public class Test1 {public static void main(String[] args) throws Exception {// TODO Auto-generated method stubStringBuilder buff = new StringBuilder();System.out.println(buff);String string = null;buff.append(string);System.out.println(buff);}
}

在这里插入图片描述

测试发现结果的确为null

在回到append方法中,如果传的字符串不为空时,会将字符串的长度和当前value数组的长度加在一起作为参数调用ensureCapacityInternal方法,获得扩容后的数组,再去调用String类的getChars方法.进入String源码,查看getChars方法

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {if (srcBegin < 0) {throw new StringIndexOutOfBoundsException(srcBegin);}if (srcEnd > value.length) {throw new StringIndexOutOfBoundsException(srcEnd);}if (srcBegin > srcEnd) {throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);}System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);}

能够看到这个方法是利用System.arraycopy方法将value数组的值加上新传进来的String字符串的拼接到新数组dst当中

最后append方法将扩容后的本实例传回去,做到了字符串拼接的效果.可以看到整个过程中真的没有创建新的对象,一切都是在对value这个数组变量进行操控.

但是仔细考虑还是会发现一些问题,因为数组一旦创建长度没法改变,无论是利用System.arraycopy方法还是Arrays.CopyOf方法,实际上都是再new一个新的数组来存放数据.在StringBuilder扩容的过程当中,虽说没有new一个新对象,但是当拼接的字符串不为null时,会new两个新的数组.而利用"+"这种形式虽说会创建一个新的字符串对象,但是每次创对象时只要再new一个新数组就行了.所以说实际上StringBuilder也会出现不断创建新的,并且回收旧的过程,只不过从对象变成了数组.那到底为什么StringBuilder会比String快那么多呢?

这时候决定查看以下反编译的结果,发现String用"+"这种方式做字符串拼接时,竟然调用了StringBuffer的append方法.what?

在这里插入图片描述

翻阅Thinking in java发现,原来String在做大量拼接时,会默认调用StringBuffer的append方法.这样一切就说通过了,String比StringBuilder慢的原因是因为在大量拼接时,它会不断的new一个新的StringBuffer类,然后调用append方法,会再new两个新的数组,这样就出现了大量的浪费资源情况,效率也比StringBuilder慢很多

2.与StringBuffer相比

原因很简单,查阅源码就能发现,StringBuilder里的append方法没有synchronized关键字,所以它为了追求速度放弃了线程的安全性,如下

@Override
public synchronized StringBuffer append(String str) {toStringCache = null;super.append(str);return this;
}
  @Overridepublic StringBuilder append(String str) {super.append(str);return this;}

super.append(str);
return this;
}

```java@Overridepublic StringBuilder append(String str) {super.append(str);return this;}

但是在单一线程的情况下,StringBuilder不会出现线程安全的问题,所以建议在单线程时使用StringBuilder会更快

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/66029.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MVCC依然可以产生幻读的原因

不同引擎mvcc实现不一样。以innodb为例的话&#xff0c;mvcc本身是通过trx_id(事务隐藏列)来实现的版本维护&#xff0c;不能读取到ReadView开启时还没提交的事务的记录。 mysql里面实际上有两种读&#xff0c;一种是“快照读”&#xff0c;比如我们使用select进行查询&#x…

TM4C 123GXL上手简介(一) 如何下载从官网下载和使用相关资料

TM4C 123GXL上手简介&#xff08;一&#xff09; 如何下载从官网下载和使用相关资料 相关网站介绍 TI官网&#xff1a;http://www.ti.com.cn/ TI中文社区&#xff1a;https://e2echina.ti.com/ 官网上可以查找到很多关于TI公司单片机的官方资料&#xff0c;而在中文论坛上会有…

Camtasia 2023破解激活版免费下载附序列号激活码

Camtasia Studio 2023破解免费下载它是一种专业屏幕录像 机和视频编辑器&#xff0c;用于屏幕录像机和视频编辑器 Web、CD-ROM 便携式媒体播放器(包括便携式媒体播放器) iPod)录制、编辑和分享高质量的屏幕视频。通过支持各种视频标准&#xff0c;您可以确保当前和未来的内容交…

Camunda 官方快速入门教程中文版(完整版)

本文为Camunda官网快速入门部分的中文版本 原文地址&#xff1a; https://docs.camunda.org/get-started/quick-start/ 0.介绍 本教程将指导您使用Camunda BPM平台建模并实现您的第一个工作流程&#xff0c;其中将使用JAVA或NodeJS作为外部客户端&#xff0c;以及使用DMN分离…

各学科、各专业、全系列软件图文、视频安装详细教程总贴——CM(changeMax)独家制作,汇总

各学科、各专业、全系列软件图文、视频安装详细教程总贴 你好&#xff0c;我是change max&#xff0c;本人写博客已有一个年头了。经过一年多的沉淀&#xff0c;我发现了一个现状&#xff1a; 对于各种专业性的技术贴各位的关注度不高&#xff0c;或者说&#xff0c;本人的教程…

Camtasia2023官方中文版免费下载

在现在的网络互联网时代&#xff0c;越来越多的人走上了自媒体的道路。有些自媒体人会自己在网络上录制精彩视频&#xff0c;也有一些人会将精彩、热门的电影剪辑出来再加上自己给它的配音&#xff0c;做成大家喜欢看的电影剪辑片段。相信不管大家是自己平时有独特的爱好也好、…

【教学类-07-06】20230302《破译电话号码-图形篇(图形固定列不重复)》(三款输入版)

效果展示 1、适合中班默写学号——有姓名 有班级&#xff0c;无学号&#xff0c;适合中班幼儿 2、适合大班幼儿默写名字——有学号&#xff0c;有班级&#xff0c;无姓名&#xff0c; 适合初学者描字&#xff08;小班、中班、大班&#xff09;——名字、学号、班级都有&#xf…

Camtasia2023简体中文标准版免费更新下载

Camtasia专业的 屏幕录制和视频剪辑软件3000多万专业人士在全球范围内使用Camtasia展示产品&#xff0c;教授课程&#xff0c;培训他人&#xff0c;以更快的速度和更吸引人的方式进行沟通和屏幕分享。使您在Windows和Mac上进行录屏和剪辑创作专业外观的视频变得更为简单。 Camt…

不用手动编程!ChatGPT帮你轻松实现单片机按键输入功能

从今年年初&#xff0c;OpenAI发布的ChatGPT已摧古拉朽之势席卷全球&#xff0c;短短两个月注册用户数就超过1亿人&#xff0c;是全世界增长速度最快的应用。很多人都说今年是AI元年&#xff0c;其实也是有一定道理的&#xff0c;之前的AI门槛相对较高&#xff0c;很多人没有机…

通过链接跳转到微信公众号关注页面

首先你查看要操作的公众号历史文章&#xff0c;将其在PC浏览器上打开&#xff0c;将其 参数值复制下来&#xff0c;然后替换这个链接地址中的参数值即可https://mp.weixin.qq.com/mp/profile_ext?actionhome&__bizMzU1NzUzNzM4NA#wechat_redirect

微信-点链接进入公众号关注页

点链接进入公众号关注页 1.找到公众号id值biz2.拼接链接3.测试 现在的公众号引流一般都只能是二维码扫码后关注&#xff0c;那么通过点击一段网页链接怎么引导用户到公众号关注页呢&#xff1f; 1.找到公众号id值biz 进入公众号&#xff0c;点击文章&#xff1a; 复制文章链…

微信公众号消息增加跳转链接

微信公众号消息增加跳转链接 背景&#xff1a; 用户在首次关注公众号后会弹出一条欢迎消息。给这条消息增加跳转的链接&#xff0c;使得用户在点击之后可以跳转 到一个你希望用户访问的页面。 解决方案&#xff1a; 根据微信开发者文档&#xff0c;找到了3种实现方式。 1…

如何用nodejs构造一个网站爬虫

爬虫是个什么东西 英文spider&#xff0c;网络爬虫&#xff08;又称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在FOAF社区中间&#xff0c;更经常的称为网页追逐者&#xff09;&#xff0c;是一种按照一定的规则&#xff0c;自动地抓取万维网信息的程序或者脚本。另外一些…

平板电脑能安装java_手机上能安装的应用,平板电脑上是不是都能安装

手机上能安装的应用&#xff0c;平板电脑上是不是都能安装以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01; 手机上能安装的应用&#xff0c;平板电脑上是不是都能安装 只要是同系统的一般都行…

元宇宙与脑机接口

今天有有幸&#xff0c;读到了几篇好文&#xff0c;有如醍醐灌顶&#xff0c;让人大开眼界与思维的同时&#xff0c;感受到极深的共鸣。特此动笔写写一些感悟&#xff0c;也是纪念这许久以来&#xff0c;少有的精神上的愉悦。 这几篇文&#xff0c;链接如下&#xff1a; 人类唯…

程序员熬过中年危机的八条建议

年关将至&#xff0c;最近发完今年最后一个版本&#xff0c;周末跟几位原同事小聚&#xff0c;侃谈人生&#xff0c;顺便谈到大家境况。有人顺利晋升&#xff0c;有人无望转岗&#xff0c;也有人面临续约淘汰。实际上&#xff0c;每个人都进入冲刺阶段&#xff0c;不管是谋生、…

转载……给新人程序员的八点建议

给新人程序员的八点建议 他结合自身经历&#xff0c;对许多刚踏入程序员行列的新人程序员&#xff0c;他给出了以下八点建议 …… 今 年已经是陈皓在程序员行业里的第十个年头了。总结这十年&#xff0c;毕业的头两年&#xff0c;陈皓在银行中昏昏沉沉中度过&#xff0c;“这…

职场7个建议 轻松抛弃同龄人

点击蓝字关注&#xff0c;回复“职级”获取知名互联网公司职级定义 昨天在IT东方会平台做了一场直播&#xff0c;很多朋友提了很多职场相关的问题&#xff0c;觉得有必须总结一下这些年一些职场习惯&#xff0c;希望这些建议可以启发到你。 那现在就开始吧&#xff0c;下面从「…

2017热点推荐:成功程序员的8个习惯

对成功的渴望或许是我们与生俱来写在基因里的一部分。成功会让人幸福&#xff0c;并且几乎每个人都在争取幸福。当我们感到幸福的时候&#xff0c;我们大脑中的化学物质会迸发积极的情感&#xff0c;激励我们获取更多的成功。 成功的职业生涯通常是指规定时间内&#xff0c;发布…

这8个习惯可以改变整个人生?

1、清晰地知道你今天的工作&#xff0c;不会迷茫磨时间&#xff1b; 早上的阳光真舒服啊&#xff0c;繁闹的街区空荡荡没有几个人&#xff0c;感觉自己平白无故地&#xff0c;比别人赚到了2个小时的自由时间。 2、有充沛的精力&#xff0c;帮你高效地完成计划&#xff1b; 早…