详解StringBuilder和StringBuffer(区别,使用方法,含源码讲解)


目录

一.为什么要使用StringBuilder和StringBuffer

字符串的不可变性

性能损耗

二.StringBuilder和StringBuffer

StringBuffer源码讲解

使用方式

三.常用方法总结

示例: 

四.StringBuilder和StringBuffer的区别


一.为什么要使用StringBuilder和StringBuffer

在引入StringBuilder和StringBuffer之前,我们可以回顾一下之前我们对于字符串的拼接操作,大多都是如下直接进行拼接:

    public static void main(String[] args) {String s = "hello";s += " world";System.out.println(s); // 输出:hello world}

 这样的操作固然是没有问题的,但是如果要说到效率的话,这样的代码效率就非常的低下了,为什么低下呢?说到这里我们就要提到字符串的相关性质了。

字符串的不可变性

String类在设计的时候就是不可改变的,我们可以在JDK1.8的源码中看见如下的注释

因此,我们平常使用的对于String字符串操作的方法,都是新建了一个对象来进行操作,想验证这个结论也很简单,我们随便选择一个方法,我们使用 “ == ” 相当于比较的是俩边变量的地址的哈希值,我们将一个字符串和对它进行大写转换后的字符串进行对比

    public static void main(String[] args) {String s = "hello";//s.toUpperCase(Locale.of(s));System.out.println( s == s.toUpperCase(Locale.of(s)));}

 输出结果:

性能损耗

我们再回顾刚才对于字符串的拼接操作,每一次拼接都要新建一个对象的, 当拼接次数非常多的时候,会造成非常严重的性能问题,我们当然也可以验证这个性能问题,使用 currentTimeMillis 方法可以直接拿到当前时刻系统的时间戳,我们可以通过一个循环来展示一下使用传统方式拼接字符串的方式会有怎么样的一个性能损耗

    public static void main(String[] args) {long start = System.currentTimeMillis();String s = " ";for(int i = 0; i < 10000; ++i){s += i;}long end = System.currentTimeMillis();System.out.println(end - start);}

输出结果:

当然这还只是10000次循环就造成了82毫秒的运行时间,实际工程中所需的循环次数往往是不可估摸的,因此使用这种方式进行拼接往往是不能完成我们的性能要求的


二.StringBuilder和StringBuffer

为了解决上述的问题,我们就可以使用StringBuilderStringBuffer来进行字符串的拼接等操作,我们可以打开API来查看什么是StringBuilder和StringBuffer

StringBuilder:

 StringBuffer:

StringBuffer源码讲解

在一般使用的时候,他们的功能大致相同,这里笔者进行讲解就只选取其中一种,整体的包含的方法,使用的技巧大多都是一样的,因此不用担心知识覆盖面不全面,笔者这里就以 StringBuffer 来举例,我们可以在IDEA中打开 StringBuffer 的源码,我们可以发现它也是被 final 修饰,继承了父类 AbstractStringBuilder 并且实现了部分接口

父类 AbstractStringBuilder 中一共俩个成员变量:

我们可以看见它的构造方法包含了不同初始化对应的操作:

使用方式

通过源码中的的super关键字结合和上述父类中的成员变量,我们可以得到以下结论:我们默认新建一个 StringBuffer 的时候实际上是新建了一个16字节的数组,我们也可以使用其他的俩个构造方法在传参的时候直接传入大小参数或者直接传入一个字符串

我们总结三种常用的初始化方式如下:

  • 不传参数,默认16字节大小的数组
  • 传入参数直接申明大小
  • 传入字符串
        StringBuffer stringBuffer1 = new StringBuffer();StringBuffer stringBuffer3 = new StringBuffer(20);StringBuffer stringBuffer2 = new StringBuffer("hello");

三.常用方法总结

我们的StringBuilderStringBuffer最大的特征就是他们内部是可变的,我们通过这俩个类去操作字符串的时候,可以不用新建一个对象,因此我们在进行字符串的拼接的时候往往都是用的这俩个类进行操作,这极大程度上有利于我们提高程运行的效率

我们再谈文章开始说的那个例子,我们使用StringBuffer中的 append 方法可以直接拼接字符,我们分别使用传统的拼接字符和这里的StringBuffer来对比拼接字符所需要的时间

    public static void main(String[] args) {long start = System.currentTimeMillis();String s = "";for(int i = 0; i < 10000; ++i){s += i;}long end = System.currentTimeMillis();System.out.println(end - start);System.out.println("=======分割行========");start = System.currentTimeMillis();StringBuffer sbf = new StringBuffer("");for(int i = 0; i < 10000; ++i){sbf.append(i);}end = System.currentTimeMillis();System.out.println(end - start);}

输出结果:

我们可以直观的发现:使用 StringBuffer 来拼接字符比直接拼接的效率提高了几十倍,而如果加多循环次数的话,这个倍数还能继续再增加,将原本程序的效率提高几百倍不是梦

除了上述的appen方法,我们将常用的方法总结如下:

方法说明
StringBuff append(String str)
在尾部追加,相当于 String += ,可以追加: boolean char char[] 、 double、 float int long Object String StringBuff 的变量
char charAt(int index)
获取 index 位置的字符
int length()
获取字符串的长度
int capacity()
获取底层保存字符串空间总的大小
void ensureCapacity(int mininmumCapacity)
扩容
void setCharAt(int index, char ch)
index 位置的字符设置为 ch
int indexOf(String str)
返回 str 第一次出现的位置
int indexOf(String str, int fromIndex)
fromIndex 位置开始查找 str 第一次出现的位置
int lastIndexOf(String str)
返回最后一次出现 str 的位置
int lastIndexOf(String str, int fromIndex)
fromIndex 位置开始找 str 最后一次出现的位置
StringBuff insert(int
offset, String str)
offset 位置插入:八种基类类型 & String 类型 & Object 类型数据
StringBuffer deleteCharAt(int index)
删除 index 位置字符
StringBuffer delete(int start, int end)
删除 [start, end) 区间内的字符
StringBuffer replace(int start, int end, String str)
[start, end) 位置的字符替换为 str
String substring(int start)
start 开始一直到末尾的字符以 String 的方式返回
String substring(int start, int end)
[start, end) 范围内的字符以 String 的方式返回
StringBuffer reverse()
反转字符串
String toString()
将所有字符按照 String 的方式返回

示例: 

    public static void main(String[] args) {StringBuilder sb1 = new StringBuilder("hello");StringBuilder sb2 = sb1;// 追加:即尾插-->字符、字符串、整形数字sb1.append(' '); // hellosb1.append("world"); // hello worldsb1.append(123); // hello world123System.out.println(sb1); // hello world123System.out.println(sb1 == sb2); // trueSystem.out.println(sb1.charAt(0)); // 获取0号位上的字符 hSystem.out.println(sb1.length()); // 获取字符串的有效长度14System.out.println(sb1.capacity()); // 获取底层数组的总大小sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123System.out.println(sb1);System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置sb1.deleteCharAt(0); // 删除首字符sb1.delete(0, 5); // 删除[0, 5)范围内的字符String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回System.out.println(str);sb1.reverse(); // 字符串逆转str = sb1.toString(); // 将StringBuffer以String的方式返回System.out.println(str);}

从上述例子可以看出:StringStringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改,因此频繁修改字符串的情况考虑使用StringBuilder

注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:

  • String变为StringBuilder: 利用StringBuilder的构造方法append()方法
  • StringBuilder变为String: 调用toString()方法

四.StringBuilder和StringBuffer的区别

我们可以打开StringBuffer的源码,我们观察到几乎每一个StringBuffer的前面都有一个synchronized来修饰StringBuffer,这里的synchronized其实就可以理解为一个锁,被synchronized修饰的方法不允许同时被多个对象在同一时刻调用,这样的设立是为了多线程的程序的安全性。

举个通俗的例子:现在有小王,小李,小红三个人想上厕所,但是厕所只有一个,小王先去上厕所,那么小李或者小红就只能等小王用完厕所出来了后,才能去上厕所

而我们的StringBuffer就是类似这样设置的,当一个对象调用被synchronized修饰的方法的时候,这个方法就会被上锁,其他对象不能使用,只有当前这个对象使用完这个方法之后,也就是解锁之后,其他对象才能访问

当我们打开StringBuilder的源码会发现我们的StringBuilder并没有这样的设置操作

总结:

也就是说StringBuffer是为了多线程的安全,但是频繁的上锁解锁会降低代码的运行效率,而StringBuilder虽然没有安全性的考虑,但是它不用开锁解锁,所以运行效率更高,我们在编程中如果需要安全性就使用StringBuffer,如果是为了高效率就使用StringBuilder




 本次的分享就到此为止了,希望我的分享能给您带来帮助,也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见

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

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

相关文章

【技巧】PDF文件如何编辑?

日常办公中我们经常会用到PDF文件&#xff0c;PDF具备很好的兼容性、稳定性及安全性&#xff0c;但却不容易编辑&#xff0c;那PDF要如何编辑呢&#xff1f; 如果打开PDF文件就只是只读的性质&#xff0c;说明文件是在线打开&#xff0c;或者通过PDF阅读器打开的&#xff0c;这…

pikachu靶场Table pikachu.member doesn’t exist:解决

背景&#xff1a; 第一次搭建pikachu靶场&#xff0c;搭建好后访问index.php后&#xff0c;尝试练习&#xff0c;发现界面显示Table pikachu.member doesn t exist&#xff0c;后来找了很多教程&#xff0c;没有解决&#xff0c;后来发现是自己没有进行初始化&#xff0c;给大家…

计算机毕业设计 基于微信小程序的“共享书角”图书借还管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

5-8输出水仙花数

#include<stdio.h> int main(){int i,j,k;int n;for(n100;n<1000;n){in/100;jn/10-i*10;kn%10;if(ni*i*ij*j*jk*k*k)printf("%d ",n);}printf("\n");return 0; }

Rust并发编程:理解线程与并发

大家好&#xff01;我是lincyang。 今天我们来深入探讨Rust中的并发编程&#xff0c;特别是线程的使用和并发的基本概念。 Rust中的线程 Rust使用线程来实现并发。线程是操作系统可以同时运行的最小指令集。在Rust中&#xff0c;创建线程非常简单&#xff0c;但与此同时&…

IOS+Appium+Python自动化全实战教程

由于公司的产品坐落于不同的平台&#xff0c;如ios、mac、Android、windows、web。因此每次有新需求的时候&#xff0c;开发结束后&#xff0c;留给测试的时间也不多。此外&#xff0c;一些新的功能实现&#xff0c;偶尔会影响其他的模块功能正常的使用。 网上的ios自动化方面的…

hadoop在本地创建文件,然后将文件拷贝/上传到HDFS

1.要$cd {对应目录}进入到对应目录&#xff0c;一般为 cd /usr/local/hadoop/ 2.创建文件&#xff0c;$sudo gedit {文件名}&#xff0c;例 sudo gedit test.txt 然后在弹出的txt文件输入内容&#xff0c;点击右上角的保存之后&#xff0c;关闭即可。 3.拷贝本地文件到HDF…

【机器学习】Nonlinear Independent Component Analysis - Aapo Hyvärinen

Linear independent component analysis (ICA) x i ( k ) ∑ j 1 n a i j s j ( k ) for all i 1 … n , k 1 … K ( ) x_i(k) \sum_{j1}^{n} a_{ij}s_j(k) \quad \text{for all } i 1 \ldots n, k 1 \ldots K \tag{} xi​(k)j1∑n​aij​sj​(k)for all i1…n,k1…K()…

阿里云99元服务器ECS经济型e实例性能如何?测评来了

阿里云服务器优惠99元一年&#xff0c;配置为云服务器ECS经济型e实例&#xff0c;2核2G配置、3M固定带宽和40G ESSD Entry系统盘&#xff0c;CPU采用Intel Xeon Platinum架构处理器&#xff0c;2.5 GHz主频&#xff0c;3M带宽下载速度384KB/秒&#xff0c;上传速度1028KB/秒&am…

深信服技术认证“SCSA-S”划重点:信息收集

为帮助大家更加系统化地学习网络安全知识&#xff0c;以及更高效地通过深信服安全服务认证工程师考核&#xff0c;深信服特别推出“SCSA-S认证备考秘笈”共十期内容&#xff0c;“考试重点”内容框架&#xff0c;帮助大家快速get重点知识~ 划重点来啦 深信服安全服务认证工程师…

ChatGPT 也并非万能,品牌如何搭上 AIGC「快班车」

内容即产品的时代&#xff0c;所见即所得&#xff0c;所得甚至超越所见。 无论是在公域的电商平台、社交媒体&#xff0c;还是品牌私域的官网、社群、小程序&#xff0c;品牌如果想与用户发生连接&#xff0c;内容永远是最前置的第一要素。 01 当内容被消费过&#xff0c;就…

〖大前端 - 基础入门三大核心之JS篇㊶〗- DOM事件传播和事件监听方法addEventListener()

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

vector的简单模拟实现_C++

目录 一、vector的数据结构 二、vector的构造 三、vector的增删查改及空间管理 四、全部代码 一、vector的数据结构 vector以线性连续空间为基础来定义数据结构以及扩展功能。vector的两个迭代器&#xff0c;分别是start和finish&#xff0c;分别指向配置得来的已被使用的空…

Javaweb之Axios的详细解析

1.3 Axios 上述原生的Ajax请求的代码编写起来还是比较繁琐的&#xff0c;所以接下来我们学习一门更加简单的发送Ajax请求的技术Axios 。Axios是对原生的AJAX进行封装&#xff0c;简化书写。Axios官网是&#xff1a;https://www.axios-http.cn 1.3.1 Axios的基本使用 Axios的…

磐舟CI使用说明及案例

整体介绍 磐舟作为一个devops产品&#xff0c;它具备基础的CI流水线功能。同时磐舟的流水线是完全基于云原生架构设计的&#xff0c;在使用时会有一些注意事项。这里首先我们要了解磐舟整体的流水线打包逻辑。 文档结构说明 一般来说&#xff0c;磐舟推荐单个业务的标准git库…

【Web】preg_match绕过相关例题wp

目录 ①[FBCTF 2019]rceservice ②[ctfshow]web130 ③[ctfshow]web131 ④[NISACTF 2022]middlerce 简单回顾一下基础 参考文章 p牛神文 preg_match绕过总的来讲就三块可利用 数组绕过、PCRE回溯次数限制、换行符 ①[FBCTF 2019]rceservice 先贴出附件给的源码 &l…

【云原生】Spring Cloud Alibaba 之 Gateway 服务网关实战开发

目录 一、什么是网关 ⛅网关的实现原理 二、Gateway 与 Zuul 的区别&#xff1f; 三、Gateway 服务网关 快速入门 ⛄需求 ⏳项目搭建 ✅启动测试 四、Gateway 断言工厂 五、Gateway 过滤器 ⛽过滤器工厂 ♨️全局过滤器 六、源码地址 ⛵小结 一、什么是网关 Spri…

某60区块链安全之Call函数簇滥用实战二学习记录

区块链安全 文章目录 区块链安全Call函数簇滥用实战二实验目的实验环境实验原理实验内容实验步骤EXP利用 Call函数簇滥用实战二 实验目的 学会使用python3的web3模块 学会并区分以太坊call、staticcall、delegatecall三种函数调用的特点 找到合约漏洞进行分析并形成利用 实验…

一套开源、强大且美观的WPF UI控件库 - HandyControl

前言 今天给大家推荐一套开源、强大且美观的WPF UI控件库&#xff1a;HandyControl。 WPF介绍 WPF 是一个强大的桌面应用程序框架&#xff0c;用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、数据绑定、样式和模板、动画效果等功能&#xff0c;让开发者可以创…

【LeetCode二叉树进阶题目】606,102,107

二叉树进阶题目 606. 根据二叉树创建字符串解题思路及实现 102. 二叉树的层序遍历解题思路及实现 107. 二叉树的层序遍历 II解题思路及实现 606. 根据二叉树创建字符串 描述 给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号…