Java | 谈谈StringBuilder的使用和细节

String、StringBuffer和StringBuilder的详解 1.值的可变性String内部的value值是final修饰的,所以,它是不可变类;因此,每次修改String的值,都会产生一个新的对象。StringBuffer和StringBuilder是可变类,它们在字符串变更的时候,不会产生新的对象。2.线程安全String是不可变类,所以它是线程安全的。StringBuilder不是线程安全的。StringBuffer是线程安全的,因为它的每个操作方法都加了synchronized同步关键字。单线程情况下,建议使用StringBuilder。 阅读详情

前言

众所周知,在Java中String对象是不可变的。不可变性会导致一系列的效率问题,例如下面几行代码,为了生成最终的结果,I 首先会和love 连接生成一个I loveString对象,然后再和java.连接,再次生成一个新的String对象(这里先不讨论编译器会做优化)。

    String str = "I ";
    str += "love ";
    str += "java.";
    System.out.println(str); 
复制代码

可以发现,为了生成最终的结果,会产生一系列的需要垃圾回收的中间对象,当操作的次数增加,就会导致很严重的性能问题,而StringBuilder便是专门为解决这一问题而出现的,StringBuilder可以将我们的每次操作都只在原对象上进行操作,因此便解决了由于生成中间String对象而导致的性能问题。

基本使用

StringBuilder的基本使用方法如下,我们每次需要创建一个StringBuilder对象,当需要进行字符串拼接操作时,只需要使用append方法即可。

    StringBuilder sb = new StringBuilder();
    sb.append("I ");
    sb.append("love ");
    sb.append("java.");
    System.out.println(sb);
复制代码

然而其实以上两种操作,经过编译器的优化,在性能上一样的,我们可以通过javap指令来进行验证,前言中的代码我放在StringBuilderStudy这个类中,然后通过一下两步进行反编译来进行验证:

    javac StringBuilderStudy.java
    javap -c StringBuilderStudy
复制代码

然后得到以下字节码结果,部分无关内容省去:

public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String I
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:/StringBuilder; 
      14: ldc           #6                  // String love
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: new           #3                  // class java/lang/StringBuilder
      26: dup
      27: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      30: aload_1
      31: invokevirtual #5                  // Method java/lang/StringBuilder.append:StringBuilder;
      34: ldc           #8                  // String java.
      36: invokevirtual #5                  // Method java/lang/StringBuilder.append:StringBuilder;
      39: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      42: astore_1
      43: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      46: aload_1
      47: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      50: return
复制代码

仔细查看很容易发现,尽管我们使用的是普通的字符串拼接操作,但编译器会自动帮我们改成StringBuilder进行操作,最终调用toString方法,然后进行输出。然而,尽管编译器会帮我们做底层优化,我们在某些情况下仍然需要自己显示使用,最常见的一个情况就是在for循环当中,例如以下代码:

    String[] strArr = {"I ", "love ", "java."};
    String res = "";
    for (String str : strArr) {
        res += str;
    }
    System.out.println(res);
复制代码

我们首先先进行反编译查看生成的字节码(有部分省略):

public static void main(java.lang.String[]);
    Code:
       0: iconst_3
       1: anewarray     #2                  // class java/lang/String
       4: dup
       5: iconst_0
       6: ldc           #3                  // String I
       8: aastore
       9: dup
      10: iconst_1
      11: ldc           #4                  // String love
      13: aastore
      14: dup
      15: iconst_2
      16: ldc           #5                  // String  java.
      18: aastore
      19: astore_1
      20: ldc           #6                  // String
      32: iload         5
      34: iload         4
      36: if_icmpge     71
      39: aload_3
      40: iload         5
      42: aaload
      43: astore        6
      45: new           #7                  // class java/lang/StringBuilder
      48: dup
      49: invokespecial #8                  // Method java/lang/StringBuilder."<init>":()V
      52: aload_2
      53: invokevirtual #9                  // Method java/lang/StringBuilder.append:StringBuilder;
      56: aload         6
      58: invokevirtual #9                  // Method java/lang/StringBuilder.append:/StringBuilder;
      61: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      64: astore_2
      65: iinc          5, 1
      68: goto          32
      71: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      74: aload_2
      75: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      78: return
复制代码

稍微读一下,可以通过68行的goto 32知道,32行便是循环的入口点,而很容易发现在循环内部,在45行处有一个new操作,说明在每次循环中为了进行字符串的拼接操作都会生成一个新的StringBuilder对象,最后再调用toString方法。这也导致了每次循环都会产生一个中间对象需要垃圾回收,影响了性能,那如果我们自己使用呢,又会是怎样?先自己写出如下代码:

    String[] strArr = {"I ", "love ", "java."};
    StringBuilder sb = new StringBuilder();
    for (String str : strArr) {
        sb.append(str);
    }
    System.out.println(sb);
复制代码

然后查看反编译生成的字节码(有删减):

public static void main(java.lang.String[]);
    Code:
       0: iconst_3
       1: anewarray     #2                  // class java/lang/String
       4: dup
       5: iconst_0
       6: ldc           #3                  // String I
       8: aastore
       9: dup
      10: iconst_1
      11: ldc           #4                  // String love
      13: aastore
      14: dup
      15: iconst_2
      16: ldc           #5                  // String  java.
      18: aastore
      19: astore_1
      20: new           #6                  // class java/lang/StringBuilder
      23: dup
      24: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      37: iload         5
      39: iload         4
      41: if_icmpge     63
      44: aload_3
      45: iload         5
      47: aaload
      48: astore        6
      50: aload_2
      51: aload         6
      53: invokevirtual #8                  // Method java/lang/StringBuilder.append:/StringBuilder;
      56: pop
      57: iinc          5, 1
      60: goto          37
      63: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      66: aload_2
      67: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      70: return
复制代码

仔细查看便可以发现,在这里的循环入口为37行,而循环内部也没有了生成中间StringBuilder对象的代码,只有循环外20行处我们自己进行的一次new操作。因此,尽管编译器会帮助我们做底层的优化,但是当在循环中等一些地方使用字符串拼接操作时,还是需要自己亲自使用StringBuilder对象进行操作,而对于return "I " + "love " + "java.";这种情况则可以依靠编译器的优化,而不需要自己费力去操作了。

使用细节

​ 我们有时可能会为了方便这样使用StringBuilder进行拼接:append("(" + name + ")"),然而这其实是一个不好的习惯,编译器并没办法识别这种情况,即自己将括号内的拼接操作转换为多次append操作,而是会生成一个中间StringBuilder对象执行拼接操作,然后再使用toString方法,因此正确的使用的方法应该是append("(").append(name).append(")"),这里不展示反编译后的字节码了,大家感兴趣可以自己试一下。

Java中String、StringBuffer和StringBuilder的区别和堆栈内存分配 Java中的String类是一个很常用,但最不注意其细节的类,因此大多数面试会那这个类做文章。比如String str = new String("hello");开辟了几个内存空间,String和StringBuffer的区别等等。下面就做一个我的理解: String是一个被final修饰的类,它是不能被继承的。StringBuffer也是被final修饰的类。 一、JVM内存划分 在java中主要存在4块内存,这些内存空间分别为:栈内存空间、堆内存空间、全局数据区、全局代码区 也可以这么说:所 阅读详情

相关推荐

linux和mac安装+配置circos(

一定要下载完这两个包,GD才会work,要不然会报错,且-modules显示也是fail。官网的教程说的很明白,但是很多包都已经过时了需要在网上找。一般来讲,所有包的安装都不会太困难,除了GD。1.是因为官网给的链接下出来的tgz无法解压。2.我的电脑安装后GD照样是fail的。,进入这个地址下一个.tgz。第二点的原因在于,官网的情况。,进入这个地址,按部就班。GD安装困难有以下几点。搞了一天终于配置成功。

xiufan1的博客 551

Android内存优化杂谈

Android内存优化是我们性能优化工作中比较重要的一环,这里其实主要包括两方面的工作: 优化RAM,即降低运行时内存。这里的目的是防止程序发生OOM异常,以及降低程序由于内存过大被LMK机制杀死的概率。另一方面,不合理的内存使用会使GC大大增多,从而导致程序变卡。 优化ROM,即降低程序占ROM的体积。这里主要是为了降低程序占用的空间,防止由于ROM空间不足导致程序无法安装。

第四维空间的专栏 1621

RAD Studio 12安装全攻略:从下载到破解InterBase的完整流程(附KeyPatch使用技巧)

本文提供RAD Studio 12的完整安装指南,包括系统要求、安装步骤及InterBase数据库的高效配置方法。详细介绍了如何使用KeyPatch工具进行许可证处理,并分享了IDE优化和开发技巧,帮助开发者快速上手这一强大的跨平台开发工具。

q6r7s8t9的博客 950

Java笔记之浅析String以及Stringbuffer

String十分常用,一般用到字符串时都会先想到String,但是String有那么好用吗!String与StringBuffer有什么区别,为什么更推荐使用Stringbuffer。带着问题来探索 首先看源码中String类与StringBuffer对比他们的构造函数可以发现一些区别String private final char value[]; public String(

ClumsyOtter的博客 424

树莓派使用 OLED 屏显示图片及文字

树莓派默认是不带显示屏的,如果想要查看系统的一些信息,需要使用电脑登录到树莓派,或者通过 HDMI 连接外接显示器查看。这样做总是有点麻烦,我们可以通过外接一个 OLED 屏来显示一些关键参数或者图片。本文将详细介绍操作方法。 OLED 模组介绍 OLED 屏主要有两种:128×32 和 128×64 ,主要颜色是白、黄、蓝。OLED 屏的特点是功耗低,价格便宜,使用 I2C 接口与主机连接。本文所使用的是 128×64 尺寸的屏幕,外形如下: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直

码到成功 3743

13、无人机网络安全攻击检测:入侵检测系统综述

本文综述了无人机网络(FANETs)中的网络安全攻击与入侵检测系统(IDS)研究进展。文章介绍了无人机网络的架构设计、路由协议分类及移动模型,重点分析了DoS、DDoS、病毒蠕虫和零日攻击等常见安全威胁,并系统梳理了网络型、主机型、签名型、异常型、混合型等多种IDS的技术原理与应用。通过对比不同攻击类型及其检测机制,提出了综合使用多类IDS、更新签名库、优化路由、加强加密和建立应急响应等安全防护建议。同时展望了人工智能、量子安全和融合安全架构等未来发展趋势,旨在为提升无人机网络的安全性提供全面的技术参考。

wasm7browser的博客 162

118-167-javajvm-stringtable-垃圾回收算法和相关概念

jvm-118-167

qq_37171694的博客 633

计算机专业保研攻略(一):个人定位与院校推荐(必看干货)

写在最前 又是一年保研季,作为过来人,我深知保研就是一场信息战。在保研过程中,需要注意的信息太多了,最初我也因为经验不足,走了不少弯路。我写下这篇博客,希望能帮助更多有需要的同学。 怎样做好保研信息分析 我想举几个发生在我身边真实的例子: A同学推免排名不如B同学,但A保研去向比B同学好很多; C同学在年级里成绩并不算突出,但他拿到了最好的offer; D、E同学纷纷圆梦北大、浙大等名校,但是他们的成绩似乎并不突出; F同学取得了目标院校夏令营offer,但没有拿到本校推免资格; G同学认为自己拿不到推免

乔卿的博客 8389

StringBuilder介绍

有些时候,需要由较短的字符串构建字符串,例如,按键或来自文件中的单词。采用字符串连接的方式达到此目的的效率比较低。每次连接字符串,都会构建一个新的String对象,既耗时,又浪费空间。使用StringBuilder类就可以避免这个问题的发生。 ...

weixin_44135991的博客 581

8 卡 GPU 服务器与 NVLink/NVSwitch 互联技术

NVLink 是一种点对点的高速互连技术,单条 NVLink 就是一条全双工双路信道,每条 NVLink 链路可以将 2 个 GPU 直连起来,并且每个 GPU 可以提供多条 NVLink 接口连接多个 GPU。另外,PCIe Switch 互联拓扑中的 GPU 之间可能存在 GPU0→Switch0→CPU0→CPU1→Switch1→GPU7 的通信链路,它的通信不可避免的存在一定的延迟,因而更适合用于对信号效率不敏感且追求性价比的使用场景,如:推理、云计算等领域。本文讨论的是单机 GPU 卡间互联。

烟云的计算 4262

Android Audio最全面试题及参考答案(7万字长文)

在 Android 音频系统中,应用通过框架层的 API 发出音频请求,这些请求经过音频服务层的处理,传递到 HAL 层,再由 HAL 层调用音频驱动层与硬件进行交互,最终实现音频的播放、录制等功能。在 Android 音频系统中,应用通过框架层的 API 发出音频请求,这些请求经过音频服务层的处理,传递到 HAL 层,再由 HAL 层调用音频驱动层与硬件进行交互,最终实现音频的播放、录制等功能。音频播放完成事件:当使用 MediaPlayer 等音频播放类播放音频时,音频播放完成后会触发这个事件。

大模型大数据攻城狮的专栏 2604

【Java】StringBuffer与StringBuilder详解

本文深度解析Java中String、StringBuilder和StringBuffer的核心差异,涵盖不可变性、线程安全、构造方法及常用操作,结合性能测试数据对比三者效率,提供预分配容量、避免隐式转换等优化策略,助你提升代码性能并轻松应对高频面试题。

m0_73941339的博客 3975

高并发网络爬虫实践(欧赔、亚盘、大小指数数据爬取)

本文通过对一个实战化的高并发网络爬虫脚本进行深度模块化剖析,展示了如何构建一个兼具性能、健壮性和易用性的数据采集工具。核心设计思想总结模块化与单一职责: 每个函数都专注于解决一个特定问题,无论是网络请求、数据解析还是文件操作。并发与效率: 通过ThreadPoolExecutor实现了高效的并发抓取,极大缩短了总耗时。健壮性与容错: 强大的重试机制、细致的异常处理和线程安全的文件写入,保证了程序在复杂网络环境下的稳定运行。断点续传: 精心设计了进度记录与恢复机制,使得大规模抓取任务变得轻松可控。

猫敷雪 481

StringBuilder和StringBuffer的区别

StringBuilder和StringBuffer都实现了继承了AbstractStringBuilder(核心类,对char[]进行操作),实现了Serializable接口(支持序列化和反序列化)和CharSequence(主要定义了length、charAt、subSquence方法) StringBuilder和StringBuffer主要不同在于,StringBuffer的append、delete、replace、length等方法前都加了synchronized关键字保证线程安全,而St

rj2017211811的博客 2万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java 中的StringBuffer类和StringBuilder类(4千字详解)

本文详细解释了 StringBuffer和StringBuilder类 的概念与使用,并讲解了 StringBuffer和StringBuilder类还有String类 相互转换的方法和区别,还举了很多例子,希望小伙伴们看后能有所收获!最后,如果本文有什么错漏的地方,欢迎大家批评指正!一起加油!!我们下一篇博文见吧!

林二月的博客 4291

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

一起学JAVA API Object String StringBuffer/StringBuilder

1 前言 亲爱的小伙伴萌,目前我们看到的是Java基础部分的一个新的部分API,这是个啥,又能做啥呢? 其实可以概括成一句话:帮助我们站在巨人的肩膀上,实现更加高效的开发,那么我们来一探究竟吧~ 2 什么是API API(Application Programming Interface,应用程序接口)是一些预先定义的函数。目的是提供应用程序与开发人员基于某软件可以访问的一些功能集,但又无需访问源码或理解内部工作机制的细节. API是一种通用功能集,有时公司会将API作为其公共开放系统,也就是公司制定自己的

程序媛泡泡的博客 5万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Java面试题之谈谈String,StringBuilder,StringBuffer区别

引言 这是一个很常见的问题了,在这里我并不是要提出什么不一样的观点,只是想通过分析源码来加深对这一问题的理解。如果您恰好也感兴趣的话,不妨随我一读。 注意:以下源码来自Oracle JDK1.8。 比较 通常关于这个问题,我们熟知的是,在字符串拼接时,千万别用String的+号来拼接,而是采用StringBuilder的append()方法来拼接。那么为什么呢? 我们先来

jinrall的专栏 813

Java中StringBuilder和StringBuffer用法以及区别

在字符串的处理中有两个类:StringBuilder和StringBuffer,这两个类都实现了对可变字符串的操作,在一定程度上可以替代String的功能。当然,在实际开发中,可能会遇到使用StringBuffer和StringBuilder之外的其他类的情况,因为它们可以通过缓存机制来避免字符串频繁创建的问题。那么,StringBuilder和StringBuffer的作用就在于,它们提供了对字符串的可变操作,可以避免生成大量的字符串对象,提高了程序效率。这个程序会生成一个长度为100000的字符串。

qwert 1521

API的含义,Scanner类的一些细节,String字符串的API及细节,以及StringBuilder的使用。

API 概念: API(Application Programming Interface)应用程序编程接口 解释: java中的API指的是sun公司为我们提供的一套标准类库,例如String或者集合类或者Random等等都是sun公司给我们提供的类。我们可以通过创建对象或者其他方式进行使用。 (注意和那个我们看的API文档进行区分,我们看的那个是个文档,是对API的一个说明书,我们要使用sun公司提供的类时,就可以去API文档查) String字符串的创建的一些细节 首先是字符串对象,java中所有被双

m0_46258226的博客 251

浅谈Java中连接字符串时使用"+"号和使用StringBuilder类的区别

主页君在留言板中看到有Javaer提出一个问题,就是Java里在连接字符串时,使用"+"号连接还是使用StringBuilder类(这个类只在J2SE5及以上版本提供,以前的版本使用StringBuffer类)连接。   为了解答这位Javaer的疑惑,可能也是许多人的疑惑,特此撰文来解答这个问题,同时也附上另外一个困扰很多Javaer的问题,就是"+"号和StringBuilder类连接字

1653

深入学习java源码之StringBuilder.indexOf()与StringBuilder.reverse()

深入学习java源码之StringBuilder.indexOf()与StringBuilder.reverse() java的toString()方法 在Java中每个类都默认继承Object类,除非声明继承某个类。而Object类中有一个叫做toString的方法。该方法返回的是该Java对象的内存地址经过哈希算法得出的int类型的值在转换成十六进制。这个输出的结果可以等同的看作Java对...

悦分享 2134

String,和StringBuffer ,StringBuilder

毕竟工作也这么久了 ,除了途虎一轮,也七七八八面试了不少大厂,像阿里、饿了么、美团、滴滴这些面试过程就不一一写在这篇文章上了。我会整理一份详细的面试过程及大家想知道的一些问题细节。

2401_83916030的博客 950

StringBuilder 和 StringBuffer 区别

之前只知道StringBuilder是线程不安全的,StringBuffer是线程安全的。但是核心细节都记不清楚,学习一下。 先上两个类的示意图 StringBuilder: StringBuffer: 区别1:StringBuffer 线程安全,StringBuilder 不安全: a. StringBuffer 使用 synchronized 修饰,使其线程安全。下图是StringBuffer的代码。 b. StringBuilder代码 区别2. 性能...

qq_32703711的博客 4717

java常用类: String,StringBuffer和StringBuilder的底层区别

java常用类: String ,StringBuilder和StringBuffer的底层区别

imbzz的博客 1087

StringBuilder的细节

原文链接 基础: String是一个不可变的类,它不能被改变。 StringBuilder是可以附加到的可变类,替换或删除字符并最终转换为a String StringBuffer是原始同步版本StringBuilder 您应该更喜欢StringBuilder所有只有一个线程访问您的对象的情况。 细节: 另外请注意,StringBuilder/Buffers这不是魔术,它们只是使用...

uj 274
上一篇: Spring Boot +Security+Redis+Vue构建后台管理系统源码免费分享
下一篇: 挑战16天搭建基于Spring Cloud电商秒杀项目,成功经验分享
java架构师小芷
博客等级 码龄6年 216粉丝 519原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值