Java StringBuilder源码剖析+面试题整理

在String中提到,如果字符串修改操作比较频繁,应该采用StringBuilder和StringBuffer类,这两个类的方法基本是完全一样的,它们的实现代码也几乎一样,唯一的不同就在于StringBuffer类是线程安全的,而StringBuilder类不是。

基本用法

创建StringBuilder对象:

StringBuilder sb = new StringBuilder();

通过append方法添加字符串:

sb.append("Hello");
sb.append(" World") ;

通过toString方法获取构建后的字符串:

System.out.println(sb.toString());

实现原理

创建

与String类似,StringBuilder类也封装了一个字符数组,定义如下:

char[] value;
int count;

与String不同,它不是final的,可以修改。另外,与String不同,字符数组中不一定所有位置都已经被使用,它有一个实例变量count,表示数组中已经使用的字符个数。

StringBuilder继承自AbstractStringBuilder,它的默认构造方法是:

public StringBuilder() {super(16);
}

其中调用父类的构造方法,父类对应的构造方法是:

AbstractStringBuilder(int capacity) {value = new char[capacity];
}

也就是说,new StringBuilder()代码内部会创建一个长度为16的字符数组,count的默认值为0。

append

append方法的代码:

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

append会直接复制字符到内部的字符数组中,如果字符数组长度不够,会进行扩展,实际使用的长度用count体现。具体来说,ensureCapacityInternal(count+len)会确保数组的长度足以容纳新添加的字符,str.getChars会复制新添加的字符到字符数组中,count+=len会增加实际使用的长度。

ensureCapacityInternal的代码如下:

private void ensureCapacityInternal(int minimumCapacity) {//overflow-conscious codeif(minimumCapacity - value.length > 0)expandCapacity(minimumCapacity);
}

如果字符数组的长度小于需要的长度,则调用expandCapacity进行扩展,其代码为:

void expandCapacity(int minimumCapacity) {int newCapacity = value.length * 2 + 2;if(newCapacity - minimumCapacity < 0)newCapacity = minimumCapacity;if(newCapacity < 0) {if (minimumCapacity < 0) //overflowthrow new OutOfMemoryError();newCapacity = Integer.MAX_VALUE;}value = Arrays.copyOf(value, newCapacity);}

扩展的逻辑是:分配一个足够长度的新数组,然后将原内容复制到这个新数组中,最后让内部的字符数组指向这个新数组,这个逻辑主要靠上面的最后一行代码实现。我们可以看出,StringBuilder的扩容是靠Arrays实现的,所以原理也一样。

这里的扩展策略是跟当前长度相关的,当前长度乘以2,再加上2,如果这个长度不够最小需要的长度,才用minimumCapacity。比如,默认长度为16,长度不够时,会先扩展到16*2+2即34,然后扩展到34*2+2即70,然后是70*2+2即142,这是一种指数扩展策略。为什么要加2?这样,在原长度为0时也可以一样工作。为什么要这么扩展呢?这是一种折中策略,一方面要减少内存分配的次数,另一方面要避免空间浪费。在不知道最终需要多长的情况下,指数扩展是一种常见的策略,广泛应用于各种内存分配相关的计算机程序中。不过,如果预先就知道需要多长,那么可以调用StringBuilder的另外一个构造方法:public StringBuilder(int capacity)

toString

toString方法的代码:

public String toString() {//Create a copy, don't share the arrayreturn new String(value, 0, count);
}

基于内部数组新建了一个String。注意,这个String构造方法不会直接用value数组,而会新建一个,以保证String的不可变性。

insert

insert是在指定索引offset处插入字符串str

public AbstractStringBuilder insert(int offset, String str) {if((offset < 0) || (offset > length()))throw new StringIndexOutOfBoundsException(offset);if(str == null)str = "null";int len = str.length();ensureCapacityInternal(count + len);System.arraycopy(value, offset, value, offset + len, count - offset);str.getChars(value, offset);count += len;return this;
}

实现思路是:在确保有足够长度后,首先将原数组中offset开始的内容向后挪动n个位置,n为待
插入字符串的长度,然后将待插入字符串复制进offset位置。

挪动位置调用了System.arraycopy()方法,将数组src中srcPos开始的length个元素复制到数组dest中destPos处。这个方法有个优点:即使src和ldest是同一个数组,它也可以正确处理。

public static native void arraycopy(Object src, int srcPos,Object dest, int destPos, int length);

+运算

Java中,String可以直接使用+和+=运算符,这是Java编译器提供的支持,背后,Java编译器一般会生成StringBuilder,+和+=操作会转换为append。比如,如下代码:

String hello = "hello";
hello+=",world";
System.out.println(hello);

背后,Java编译器一般会转换为:

StringBuilder hello = new StringBuilder("hello");
hello.append(", world");
System.out.println(hello.toString());

不过,在稍微复杂的情况下,Java编译器可能没有那么智能,它可能会生成过多的StringBuilder,尤其是在有循环的情况下,在循环内部,每一次+=操作,都会生成一个StringBuilder。所以,对于简单的情况,可以直接使用String的+和+=,对于复杂的情况,尤其是有循环的时候,应该直接使用StringBuilder。

八股考点

String、StringBuffer、StringBuilder 的区别?

String:用于字符串操作,属于不可变类;【补充:String不是基本数据类型,是引用类型,底层用char数组实现的】
StringBuilder:与StringBuffer类似,都是字符串缓冲区,但线程不安全;
StringBuffer:也用于字符串操作,不同之处是StringBuffer 属于可变类,对方法加了同步锁,线程安全(补充说明:StringBuffer中并不是所有方法都使用了Synchronized修饰来实现)

执行效率:StringBuilder>StringBuffer>String

String中“+”和StringBuffer中的 append会有性能上的差别吗?

会有性能上的差别。
在Java中,String对象是不可变的,也就是说每次使用"+“运算符连接字符串时,都会创建一个新的String对象,这就涉及到内存分配和垃圾回收,如果在循环或频繁操作中使用”+"进行字符串拼接,会大大降低性能。
而StringBuffer和StringBuilder的对象是可变的,append方法实际上是在原有的字符序列后面添加字符,不会创建新的对象,所以在进行大量或复杂的字符串操作时,使用StringBuffer或StringBuilder的性能要高于使用String的"+"。
另外,StringBuffer是线程安全的,而StringBuilder是非线程安全的,所以在单线程环境下,StringBuilder的性能会更高一些。

final修饰 StringBuffer后还可以 append 吗?

可以。final修饰的是一个引用变量,那么这个引用始终只能指向这个对象,但是这个对象内部的属性是可以变化的。

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

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

相关文章

windows系统安装VMware 虚拟机全过程介绍

在Windows系统上安装VMware Workstation 16 Pro的全过程可以分为以下几个步骤&#xff1a; 1. 准备工作&#xff1a; - 确保您的Windows系统满足VMware Workstation 16 Pro的最低系统要求。VMware Workstation 16 Pro支持Windows 10、Windows 11、Windows Server 20…

Java实现免税店商城管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.2 研究方法 三、系统展示四、核心代码4.1 查询免税种类4.2 查询物品档案4.3 新增顾客4.4 新增消费记录4.5 审核免税 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的免税店商城管理系…

RK3568笔记十四:yolov8pose部署

若该文为原创文章&#xff0c;转载请注明原文出处。 本篇参考山水无移大佬文章&#xff0c;并成功部署了yolov8pose在RK3568板子上&#xff0c;这里记录下全过程。 在此特感谢所有分享的大佬&#xff0c;底部附大佬的链接。 一、环境 1、平台&#xff1a;rk3568 2、开发板: …

c++ STL系列——(六)multimap

C标准模板库&#xff08;STL&#xff09;是C编程中不可或缺的一部分&#xff0c;它提供了一系列的容器、算法和函数模板&#xff0c;以简化常见的数据结构和算法的实现。在STL中&#xff0c;multimap是一个非常有用的容器&#xff0c;它提供了一种键值对的存储方式&#xff0c;…

牛客错题整理——C语言(实时更新)

1.以下程序的运行结果是&#xff08;&#xff09; #include <stdio.h> int main() { int sum, pad,pAd; sum pad 5; pAd sum, pAd, pad; printf("%d\n",pAd); }答案为7 由于赋值运算符的优先级高于逗号表达式&#xff0c;因此pAd sum, pAd, pad;等价于(…

QAnything之BCEmbedding技术路线

QAnything和BCEmbedding简介 QAnything[github]是网易有道开源的检索增强生成式应用&#xff08;RAG&#xff09;项目&#xff0c;在有道许多商业产品实践中已经积累丰富的经验&#xff0c;比如有道速读和有道翻译。QAnything是一个支持任意格式文件或数据库的本地知识库问答系…

java微服务面试篇

目录 目录 SpringCloud Spring Cloud 的5大组件 服务注册 Eureka Nacos Eureka和Nacos的对比 负载均衡 负载均衡流程 Ribbon负载均衡策略 自定义负载均衡策略 熔断、降级 服务雪崩 服务降级 服务熔断 服务监控 为什么需要监控 服务监控的组件 skywalking 业务…

Java ‘Elasticsearch‘ 操作

依赖 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-elasticsearch --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</ar…

【开源】SpringBoot框架开发农家乐订餐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户2.2 管理员 三、系统展示四、核心代码4.1 查询菜品类型4.2 查询菜品4.3 加购菜品4.4 新增菜品收藏4.5 新增菜品留言 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的农家乐订餐系统&#xff0c…

Ubuntu Desktop - scrolling (Terminal 缓存更多终端历史输出内容)

Ubuntu Desktop - scrolling [Terminal 缓存更多终端历史输出内容] 1. ubuntu-14.04.5-desktop-amd64.iso2. ubuntu-16.04.3-desktop-amd64.isoReferences Terminal -> 右键 Profiles -> Profile Preferences 1. ubuntu-14.04.5-desktop-amd64.iso 2. ubuntu-16.04.3-de…

Java 与 JavaScript 的区别与联系

Java 和 JavaScript 两种编程语言在软件开发中扮演着重要的角色。尽管它们都以“Java”命名&#xff0c;但实际上它们是完全不同的语言&#xff0c;各有其独特的特点和用途。本文将深入探讨 Java 和 JavaScript 的区别与联系&#xff0c;帮助大家更好地理解它们在编程世界中的作…

【技巧】Allegro实用技巧之模块复用

需求分析&#xff1a;使用Allegro软件进行PCB Layout设计时&#xff0c;当电路图中有很多路相同的模块&#xff0c;使用模块复用的的操作方法&#xff0c;可以显著提高工作效率&#xff0c;同时也可以使PCB布局在整体上显得美观。下面来讲述这个方法。 具体方法及说明&#xf…

2.13作业

数组练习 1、选择题 1.1、若有定义语句&#xff1a;int a[3][6]; &#xff0c;按在内存中的存放顺序&#xff0c;a 数组的第10个元素是D A&#xff09;a[0][4] B) a[1][3] C)a[0][3] D)a[1][4] 1.2、有数组 int a[5] {10&#xff0c;20&#xff0c;30&#xff0c;40&#xf…

【linux系统体验】-ubuntu简易折腾

ubuntu 一、终端美化二、桌面美化2.1 插件安装2.2 主题和图标2.3 美化配置 三、常用命令 以后看不看不重要&#xff0c;咱就是想记点儿东西。一、终端美化 安装oh my posh&#xff0c;参考链接&#xff1a;Linux 终端美化 1、安装字体 oh my posh美化工具可以使用合适的字体&a…

2.11学习总结

有效点对https://www.acwing.com/problem/content/description/5472/ 给定一个 n&#xfffd; 个节点的无向树&#xff0c;节点编号 1∼n1∼&#xfffd;。 树上有两个不同的特殊点 x,y&#xfffd;,&#xfffd;&#xff0c;对于树中的每一个点对 (u,v)(u≠v)(&#xfffd;,…

jsp计算机线上教学系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 计算机线上教学系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5…

Java强训day19(选择题编程题)

选择题 编程题 题目1 import java.util.Scanner;public class Main {public static int res(int n) {int sum 0;//n 10while (n > 1) {sum n / 3;n n / 3 n % 3;//借空汽水瓶if (n 2) {sum 1;return sum;}}return sum;}public static void main(String[] args) {…

Linux系统c/c++开发环境配置

安装LLVM全家桶及CMAKE 输入以下命令&#xff0c;安装clang&#xff0c;clangd&#xff0c;lldb及cmake。 sudo apt install clang clangd lldb cmake yukeyangDESKTOP-QFK2F47:~/myfiles/test$ sudo apt install clang clangd lldb cmake [sudo] password for yukeyang: Re…

2024-02-13 Unity 编辑器开发之编辑器拓展4 —— EditorGUIUtility

文章目录 1 EditorGUIUtility 介绍2 加载资源2.1 Eidtor Default Resources2.2 不存在返回 null2.3 不存在则报错2.4 代码示例 3 搜索框查询、对象选中提示3.1 ShowObjectPicker3.2 PingObject3.3 代码示例 4 窗口事件传递、坐标转换4.1 CommandEvent4.2 GUIPoint 和 ScreenPoi…

[机缘参悟-156] :一个软件架构师对佛学的理解 -22- 佛教经典的主要思想之《心经》:心经不是唯心主义,更不是迷信,摆脱对佛教的误解

目录 一、概述 二、位置 三、主要思想 3.1 主要思想 3.2 心经的本质 3.3 心经与唯心主义 3.4 心经与心理学 四、修行方法 五、现实意义 一、概述 心经&#xff0c;全称《般若波罗蜜多心经》&#xff0c;是佛教中最重要的经典之一&#xff0c;属于般若波罗蜜多&#x…