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

回答重点

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之后就是这样实现的,但是你可以假装不知道呀,装的像你自己想出来的优化,你看看这多细呀~疯狂加分!

相关推荐
vipxieliang14 分钟前
ValidX 验证器缓存机制:如何提升验证性能
java·spring boot
未秃头的程序猿25 分钟前
Spring Cloud Gateway 做统一加解密,我在请求体上栽了三天
java·后端·架构
Rain的Java大神之路25 分钟前
别再上来就堆 Redis!点赞系统从打挂数据库到 18w 写峰值,我把这套方案讲透了
java·后端·面试
SimonKing29 分钟前
开源文档解析天花板 MinerU 4.0:PDF / 图片 / Office 等任意文档都支持
java·后端·程序员
小oo呆33 分钟前
【学习心得】Python函数参数中的两个特殊分隔符
开发语言·python
咖啡八杯34 分钟前
Spring MessageSource 国际化消息解析流程
java·后端·spring·架构·框架·若依
x10n939 分钟前
微软 VC++ 运行库合集VCRedistPack
开发语言·c++·microsoft·vc++运行库·dll报错
qz_Serene43 分钟前
C++:string(底层,常用接口,具体题目,模拟实现)
开发语言·c++
NiceBlueChai44 分钟前
Qt 跨线程传递多容器嵌套结构:一次 Release 实测
开发语言·qt