【Java基础面试题027】Java的StringBuilder是怎么实现的?

news/2024/12/24 1:33:54 标签: java, 开发语言

回答重点

StringBuilder主要是为了解决String对象的不可变性问题,还有单线程环境下StringBuffer的性能问题。提供了高效动态的字符串拼接和修改操作。大致需要实现append、insert等功能

大致核心实现如下:

  • 内部使用字符数组(char[] value)来存储字符序列
  • 通过方法如append()、insert()等操作,直接修改内部的字符数组,而不会像String那样创建新的字符串常量池对象
  • 每次进行字符串操作时,如果当前容量不足,它会通过扩展数组容量来容纳新的字符,按2倍的容量扩展,以减少扩展次数,提高性能

扩展知识

深入剖析StringBuilder

对于这类题目,因为已经有现有的实现作为参考,所以回答诸如此类的问题,不要急,先回想一下平日用这个StringBuilder都用了哪些方法

可以看我这一篇博客:【Java】StringBuilder类和StringBuffer类的简单教程-CSDN博客

  • append
  • insert
  • delete
  • replace
  • charAt
  • ...

大致就这么几个,每必要说太全,这不是小学课文背诵,关键方法提出来就行了

脑子浮现这几个方法后哦,直接按照上述的回答重点说出来即可。

实际上StringBuilder底层使用char数组来存储字符,并且用count来记录存放的字符数。

回答重点提到了char数组,这里可能会被面试官插入问:String底层不也是用char数组存放的吗?二者有啥区别?

展示的机会就来了!

String是不可变类,内部的成员变量char[]被final修饰了,所以是不可变的,是典型的Immutable类,因此其不可变性,保证了线程安全,能实现字符串常量池等

OK,咱们继续!

由于StringBuilder底层用char[] 存放字符,而数组是连续内存结构,为了防止频繁地复制和申请内存,需要提供capacity参数在初始化数组的时候设置大小为16,这样在预先已经知晓大字符串的情况下,可以减少数组的扩容次数,有效提升效率

这里一定要点破:数组是连续内存的结构,并且要体现出你有节省内存和提高效率的意识,如果了解HashMap应该会有经验

我们来看下调用AbstractStringBuilder这个父类的构造器

可以看到,就是直接new申请数组没啥花头

append

我们来看下append操作

可以看到append有多种实现,毕竟我们平日里啥类型都直接append,那底层是怎么实现这些类型转换的呢?

我们拿append(int)来举个例子,其他类型本地都是一样的

获取参数的位数

并没有用复杂的位运算,用的是查表法,数组中列出各个位数的边界值,然后根据数组下标判断出位数

如果是负数,要加一位符号位

判断是否扩容

判断条件:(原数组长度 + 新整数位数) - 原数组长度 > 0

如果长度不够,新建指定大小数组并复制

扩容两倍 + 2,多的2是用来微调的,考虑空间使用和性能的平衡

主要逻辑在途中标识了,将上面主要思路说一下即可

面试官可能会问:怎么扩容的呀?

先扩容两倍+2,Arrays.copyOf()拷贝

insert

先转为字符串

delete

总结

这样看下来,想必对 StringBuilder的内部实现已经很清晰了吧!就是数组的操作,而数组的特性就是内存连续,下标访问快。


针对内存连续这点,又要保持StringBuilder的动态性,那不可避免的就需要扩容操作,扩容操作简单来说就是申请一个更大char数组,把老char数组的数据拷贝过去。


对了,从源码来看,StringBuilder没有实现缩容操作。

所以回答这个设计题的时候,先说下需要实现哪些关键方法:append、delete 等等,然后点明底层是char数组实现,在执行append、insert等操作的时候需要先判断数组容量是否足够容纳字符来判断是否需要扩容,然后修改之类的操作就是调用System.arraycopy来完成字符串的变更。


因为原生的 StringBuilder 没有实现缩容操作,所以你可以提一下在 delete的时候,判断下,如果删除的字符过多,为了节省内存,实现缩容的操作。


然后还可以再提一下,char 数组是可以优化的,底层可以用byte 数组+一个 coder 标志位来实现,这样更节省内存,因为char占用两个字节,这样对于latin 系的字符来说,太大了,就很浪费,所以用 byte 数组,然后配备一个 coder来标识所用的编码。


嘿嘿,其实jdk9之后就是这样实现的,但是你可以假装不知道呀,装的像你自己想出来的优化,你看看这多细呀~疯狂加分!


http://www.niftyadmin.cn/n/5797196.html

相关文章

基于python+django的旅游信息网站-旅游景点门票管理系统

标题:基于 PythonDjango 的旅游信息网站-旅游景点门票管理系统 内容:1.摘要 基于 PythonDjango 的旅游信息网站-旅游景点门票管理系统的摘要: 随着旅游业的快速发展,旅游景点门票管理系统的重要性日益凸显。本文旨在设计并实现一个基于 PythonDjango 的…

基于SpringBoot滑雪场管理系统的设计与实现(文末附源码)

博主介绍:✌全网粉丝50W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围:SpringBoot、Vue、SSM、HLM…

以太网 Ethernet 报文解析

以太网 Ethernet 报文解析 使用canoe 发送报文。解析这个报文 参考资料 IPv4报文协议 链接: https://blog.csdn.net/m0_61643743/article/details/128509490 UDP 报文协议 链接: https://blog.csdn.net/weixin_43142797/article/details/105648071 https://fasionchan.com/ne…

《计算机组成及汇编语言原理》阅读笔记:p28-p47

《计算机组成及汇编语言原理》学习第 3 天,p28-p47 总结,总计 20 页。 一、技术总结 1.Virtual Machine 2.stack 3.The fetch-execute Cycle 在控制单元(Control Unit, CU)里面有一个指令寄存器(Instruction Register, IR)和一个程序计数器(Program…

探索数据可视化的利器:Matplotlib

探索数据可视化的利器:Matplotlib 引言 在数据科学和机器学习领域中,有效的数据可视化是理解和传达信息的关键。Python拥有许多优秀的可视化库,其中Matplotlib是最基础也是最强大的之一。它不仅为其他高级可视化库(如Seaborn、P…

JUC并发工具---并发容器

HashMap为什么是线程不安全的 import java.util.HashMap; /*** 由于 HashMap 的线程不安全性,最终的 HashMap 值可能不符合预期。* 例如,预期值应该是 0(因为增加和减少操作相互抵消),但实际上可能得到一个不同的值。…

Android 蓝牙Bluedroid线程池设计思路介绍

零. 前言 由于Bluedroid的介绍文档有限,以及对Android的一些基本的知识需要了(Android 四大组件/AIDL/Framework/Binder机制/JNI/HIDL等),加上需要掌握的语言包括Java/C/C++等,加上网络上其实没有一个完整的介绍Bluedroid系列的文档,所以不管是蓝牙初学者还是蓝牙从业人员…

适用于.net的操作excel的库

目录 目录 知识点概要 知识点具体说明(使用步骤、解释) 使用场景及示例 1. EPPlus 2. NPOI 3. ClosedXml 4. SpreadsheetLight 5.ExcelDataReader 开源库 6. ExcelDataWriter 总结 知识点概要 使用Excel来导入和导出数据,在日常工作中使用频率是相当高的&…