JAVA面试题 StringBuffer和StringBuilder的区别,从源码角度分析?

String StringBuffer和StringBuilder区别之源码解析 String StringBuffer和StringBuilder 区别之源码解析 从源码角度简单对它们之间的区别进行了验证 立即下载

面试官Q1:请问StringBuffer和StringBuilder有什么区别?

这是一个老生常谈的话题,笔者前几年每次面试都会被问到,作为基础面试题,被问到的概率百分之八九十。下面我们从面试需要答到的几个知识点来总结一下两者的区别有哪些?

  • 继承关系?

  • 如何实现的扩容?

  • 线程安全性?

继承关系

从源码上看看类StringBuffer和StringBuilder的继承结构:

 

从结构图上可以直到,StringBuffer和StringBuiler都继承自AbstractStringBuilder类

 

如何实现扩容

StringBuffer和StringBuiler的扩容的机制在抽象类AbstractStringBuilder中实现,当发现长度不够的时候(默认长度是16),会自动进行扩容工作,扩展为原数组长度的2倍加2,创建一个新的数组,并将数组的数据复制到新数组。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

public void ensureCapacity(int minimumCapacity) {

    if (minimumCapacity > 0)

        ensureCapacityInternal(minimumCapacity);

}

 

/**

* 确保value字符数组不会越界.重新new一个数组,引用指向value

*/   

private void ensureCapacityInternal(int minimumCapacity) {

    // overflow-conscious code

    if (minimumCapacity - value.length > 0) {

        value = Arrays.copyOf(value,

                newCapacity(minimumCapacity));

    }

}

 

/**

* 扩容:将长度扩展到之前大小的2倍+2

*/   

private int newCapacity(int minCapacity) {

    // overflow-conscious code   扩大2倍+2

    //这里可能会溢出,溢出后是负数哈,注意

    int newCapacity = (value.length << 1) + 2;

    if (newCapacity - minCapacity < 0) {

        newCapacity = minCapacity;

    }

    //MAX_ARRAY_SIZE的值是Integer.MAX_VALUE - 8,先判断一下预期容量(newCapacity)是否在0<x<MAX_ARRAY_SIZE之间,在这区间内就直接将数值返回,不在这区间就去判断一下是否溢出

    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)

        ? hugeCapacity(minCapacity)

        : newCapacity;

}

 

/**

* 判断大小,是否溢出

*/

private int hugeCapacity(int minCapacity) {

    if (Integer.MAX_VALUE - minCapacity < 0) { // overflow

        throw new OutOfMemoryError();

    }

    return (minCapacity > MAX_ARRAY_SIZE)

        ? minCapacity : MAX_ARRAY_SIZE;

}

 

线程安全性

我们先来看看StringBuffer的相关方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

@Override

public synchronized StringBuffer append(long lng) {

    toStringCache = null;

    super.append(lng);

    return this;

}

 

/**

 * @throws StringIndexOutOfBoundsException {@inheritDoc}

 * @since      1.2

 */

@Override

public synchronized StringBuffer replace(int start, int end, String str) {

    toStringCache = null;

    super.replace(start, end, str);

    return this;

}

 

/**

 * @throws StringIndexOutOfBoundsException {@inheritDoc}

 * @since      1.2

 */

@Override

public synchronized String substring(int start) {

    return substring(start, count);

}

 

@Override

public synchronized String toString() {

    if (toStringCache == null) {

        toStringCache = Arrays.copyOfRange(value, 0, count);

    }

    return new String(toStringCache, true);

}

从上面的源码中我们看到几乎都是所有方法都加了synchronized,几乎都是调用的父类的方法.,用synchronized关键字修饰意味着什么?加锁,资源同步串行化处理,所以是线程安全的。

 

我们再来看看StringBuilder的相关源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

@Override

public StringBuilder append(double d) {

    super.append(d);

    return this;

}

 

/**

 * @since 1.5

 */

@Override

public StringBuilder appendCodePoint(int codePoint) {

    super.appendCodePoint(codePoint);

    return this;

}

 

/**

 * @throws StringIndexOutOfBoundsException {@inheritDoc}

 */

@Override

public StringBuilder delete(int start, int end) {

    super.delete(start, end);

    return this;

}

StringBuilder的源码里面,基本上所有方法都没有用synchronized关键字修饰,当多线程访问时,就会出现线程安全性问题。

 

为了证明StringBuffer线程安全,StringBuilder线程不安全,我们通过一段代码进行验证:

测试思想

  • 分别用1000个线程写StringBuffer和StringBuilder,

  • 使用CountDownLatch保证在各自1000个线程执行完之后才打印StringBuffer和StringBuilder长度,

  • 观察结果。

测试代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

import java.util.concurrent.CountDownLatch;

 

public class TestStringBuilderAndStringBuffer {

    public static void main(String[] args) {

        //证明StringBuffer线程安全,StringBuilder线程不安全

        StringBuffer stringBuffer = new StringBuffer();

        StringBuilder stringBuilder = new StringBuilder();

        CountDownLatch latch1 = new CountDownLatch(1000);

        CountDownLatch latch2 = new CountDownLatch(1000);

        for (int i = 0; i < 1000; i++) {

            new Thread(new Runnable() {

                @Override

                public void run() {

                    try {

                        stringBuilder.append(1);

                    } catch (Exception e) {

                        e.printStackTrace();

                    } finally {

                        latch1.countDown();

                    }

                }

            }).start();

        }

        for (int i = 0; i < 1000; i++) {

            new Thread(new Runnable() {

                @Override

                public void run() {

                    try {

                        stringBuffer.append(1);

                    } catch (Exception e) {

                        e.printStackTrace();

                    } finally {

                        latch2.countDown();

                    }

 

                }

            }).start();

        }

        try {

            latch1.await();

            System.out.println(stringBuilder.length());

            latch2.await();

            System.out.println(stringBuffer.length());

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

测试结果

  • StringBuffer不论运行多少次都是1000长度。

  • StringBuilder绝大多数情况长度都会小于1000。

  • StringBuffer线程安全,StringBuilder线程不安全得到证明。

总结一下

  • StringBuffer和StringBuilder都继承自抽象类AbstractStringBuilder。

  • 存储数据的字符数组也没有被final修饰,说明值可以改变,且构造出来的字符串还有空余位置拼接字符串,但是拼接下去肯定也有不够用的时候,这时候它们内部都提供了一个自动扩容机制,当发现长度不够的时候(默认长度是16),会自动进行扩容工作,扩展为原数组长度的2倍加2,创建一个新的数组,并将数组的数据复制到新数组,所以对于拼接字符串效率要比String要高。自动扩容机制是在抽象类中实现的。

  • 线程安全性:StringBuffer效率低,线程安全,因为StringBuffer中很多方法都被 synchronized 修饰了,多线程访问时,线程安全,但是效率低下,因为它有加锁和释放锁的过程。StringBuilder效率高,但是线程是不安全的。

 

    QQ交流群: 点击 有任何问题可以加群交流   

    Java最新一线架构技术讲解请:点击 内容实用 讲解简单易懂

CATIA_DELMIA_V5R2019安装包下载及安装教程破解 CATIA_V5R2019/DELMIA_V5R2019安装包下载及安装教程破解 阅读详情

相关推荐

禅道二次开发(一):从零搭建本地开发与调试环境

本文详细介绍了禅道二次开发的第一步:从零搭建本地开发与调试环境。通过部署官方一键安装包、配置端口与防火墙、连接数据库、设置Samba文件共享,并最终在VSCode中配置PHP智能感知与Xdebug调试,手把手教你建立一个隔离、高效的专属开发工作台,为后续的代码修改与功能扩展奠定坚实基础。

weixin_29003437的博客 323

面试汇总——JavaSE——面向对象(三)

文章目录面向对象(三)类请说明静态变量存在什么位置?请你解释一下类加载机制,双亲委派模型,好处是什么?请你谈谈StringBuffer和StringBuilder有什么区别,底层实现上呢?【Java基础一,数据类型】String请说明String是否能能继承?static变量请说明”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?重载请说明重载和重写的区别,相同参数不同返回值能重载吗?面向对象请列举你所知道的Object类的方法并简要说明

赶路de人的博客 299

偷懒必备:3种方法快速移植MFC界面资源(含.rc文件打不开解决方案)

本文针对MFC桌面应用开发,详细介绍了三种快速移植界面资源的实战方法:直接编辑.rc文件、利用Visual Studio“添加现有项”进行可视化挂载,以及双实例拖拽应急方案。文章重点剖析了.rc文件无法打开的常见问题,提供了通过修复rc.exe等关键文件来根治此问题的解决方案,帮助开发者高效复用资源,规避ID冲突等陷阱。

weixin_28358083的博客 273

九阳真经-java基础面试

java基础 集合 整体框架 通用实现 Iterable(接口)接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素 ├Collection(接口) ├List列表(接口)有序的 collection(也称为序列),允许重复的元素 │├LinkedList(实现类)使用双向链表实现存储,允许所有元素(包括 null)。非线程安全,要保证同步,可以使用List list = Collections.synchronizedList(new LinkedL...

weixin_38378847的博客 372

M2DGR数据集在主流SLAM框架中的实战配置指南:从ORB-SLAM到FAST-LIO的完整流程

本文提供了M2DGR多传感器数据集在主流SLAM框架中的实战配置指南。详细介绍了从ORB-SLAM、VINS-Mono等视觉/视觉惯性框架,到A-LOAM、FAST-LIO等激光/激光惯性框架的完整配置流程、参数调整要点及常见问题解决方案。通过实际测试对比,分析了各算法在M2DGR数据集上的表现,为机器人定位与建图研究提供了宝贵的实战经验。

k9l0m1的博客 481

如何利用Arcgis进行地统计学分析(三):空间插值方法选择与优化

本文深入探讨了在Arcgis中进行地统计学分析时,如何根据探索性数据分析(EDA)结果科学选择与优化空间插值方法。文章对比了IDW、RBF、克里金等主流方法的适用场景与核心参数,并通过实战案例详解了从数据诊断到模型调优的完整流程,强调结合半变异函数与趋势分析进行“对症下药”,以提升插值结果的精度与可靠性。

weixin_29281915的博客 120

ArrayList和StringBuilder的扩容机制

我们知道,无论是ArrayList还是StringBuilder,其内部存储机制都是数组。数组在查找的时候有明显的优势,但是在插入或者删除的时候比较麻烦,涉及到扩容机制。下面我们来看一下ArrayList和StringBuilder的扩容机制有什么区别。 1. ArrayList的扩容机制 在了解扩容机制之前,我们先来看一下ArrayList的属性 public class ArrayList<E> extends AbstractList<E> implem

haohulala的博客 825

保姆级教程:在S32K312上配置C40驱动,实现Flash读写(基于RTD 4.4.2)

本文详细介绍了在S32K312微控制器上配置C40驱动实现Flash读写的全流程,基于RTD 4.4.2库。内容涵盖环境搭建、外设配置、Flash操作实战代码及高级应用场景,特别针对LLD驱动和FLS存储操作中的常见问题提供了解决方案,帮助开发者快速掌握嵌入式Flash存储技术。

weixin_28684757的博客 255

StringBuilder 和 StringBuffer 的初始容量及扩容机制

StringBuffer 和 StringBuilder 扩容机制相同,初始化容量机制相同。两者安全性不同,效率不同,更多可以参考String、StringBuilder、StringBuffer的四大区别解析_极品小學生的博客-优快云博客。

weixin_63426509的博客 1801

gcc/g++ 链接库的编译与链接

gcc/g++ 链接库的编译与链接 surgewong@gmail.com http://blog.youkuaiyun.com/surgewong       程序编译一般需要经预处理、编译、汇编和链接几个步骤。在实际应用中,有些公共代码需要反复使用,就把这些代码编译成为“库”文件。在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中,这种库称为静态(链接)库,其特点是可

Surge 4万+

python调用hypermesh调用tcl_TclTk如何调用HyperMesh运行tcl脚本文件

#Tcl/Tk编写界面部分set t [toplevel .tp]focus $tgrab $tset Filename "E:/CAE_Tech/process_files/88/Example.tcl"set Font "Times 12 bold"wm title $t "Call HyperMesh"wm attribute $t -topmost 1wm withdraw $tset t...

weixin_39541681的博客 1600

JAVA中的Stringbuilder和Stringbuffer的扩容机制

一次追加长度不仅超过初始容量,而且按照 当前容量*2+2 扩容一次也不够,其容量会直接扩容到与所添加的。StringBuffer 的有参构造初始容量为:字符串参数的长度+16。一次追加长度超过当前容量,则会按照 当前容量*2+2 扩容一次。之后再追加的话,还会按照 当前容量*2+2进行扩容。有参和无参扩容方法都一样的。都是从当前容量开始扩容。

qq_64250622的博客 605

手把手完整实现STM32+NB-IoT+MQTT+ThingsCloud云平台+手机APP(Android或iOS)及微信小程序及Web app 应用

本教程以远程温湿度显示及点灯作为示例。最终效果实现本地OLED显示屏、云平台和手机APP、微信小程序和Web App可远程查看温湿度数据,并可远程控制LED灯亮灭。以此完成基于MQTT协议的NB-IoT远程发布订阅数据,以此在本教程基础上可扩展开发更多的功能。

嵌入式阿齐Archie 2万+

阿里JAVA面试题剖析-如何从源码角度分析StringBuffer和StringBuilder的区别?

面试官Q1:请问StringBuffer和StringBuilder有什么区别? 这是一个老生常谈的话题,笔者前几年每次面试都会被问到,作为基础面试题,被问到的概率百分之八九十。下面我们从面试需要答到的几个知识点来总结一下两者的区别有哪些? 继承关系? 如何实现的扩容? 线程安全性? 继承关系 从源码上看看类StringBuffer和StringBuilde...

Java666999的博客 319

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

String StringBuilder StringBuffer区别以及源码分析

1. Spring/SpringBuilder/SpringBuffer 区别 1.1 String String 对象一旦创建之后就是不可变的,不可变的! 问题:既然String 对象是不可变的,那么其包含的常用修改值的方法是如何实现的呢? Demo substring(int,int) 字符串截取 split(String,int) 字符串分割 toLowerCase() 字符串所有字母小写 ... 其实,这些方法底层都是通过重新创建一个String 对象来接收变动后的字

兴趣使然的草帽路飞 9839

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

从源码的角度讲下String、StringBuilder和StringBuffer的区别

String:不可变性是其核心特性,适合存储常量字符串。每次修改都会生成新对象,性能较低。可变性是其核心特性,适合单线程环境下频繁修改字符串。动态扩容机制保证了高效的内存使用。在StringBuilder的基础上增加了线程安全机制。由于加锁操作,性能略低于StringBuilder。五、选择建议如果字符串内容不经常变化,使用String。如果在单线程环境下频繁修改字符串,使用StringBuilder。如果在多线程环境下频繁修改字符串,使用StringBuffer或者。

weixin_45762066的博客 710

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

面试题系列之String,Stringbuffer,StringBuilder的区别(源码分析)

记得之前参加面试的时候被问到过String,Stringbuffer,StringBuilder的区别。我当时回答String是不可变的字符串,Stringbuffer,StringBuilder是可变的字符串,Stringbuffer是线程安全的,StringBuilder不是线程安全的,所以不能同步访问。心里想这下稳了,然后就没有然后了。现在想想这样回答别人能录用才怪。所以今天就从源码的角度剖...

江夏、的博客 1413

【Java】从源码角度分析String,StringBuffer和StringBuilder

很多人都知道String是不可变的,StringBuffer和StringBuilder是可变的,那么为什么呢? 首先我们确定一个概念性问题,什么是不可变对象! 什么是不可变对象:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能...

weixin_44195108的博客 314

通过源码分析String、StringBuffer和StringBuilder

0x00 简介又翻出来了在15年整理的笔记了。感觉当初还是挺较真的。自己对String的理解总是存在着不同程度的误差,经常处于一知半解的状态,而且对其内部的原理也不是特别清楚,碰巧又和同学聊起这个知识点,秉承爱折腾的原则,在论文答辩之际详细整理一下。0x01 说明最初听说的String、StringBuffer和StringBuilder三者之间的区别主要是下面这个版本(略作总结): String:

木东居士 930

常见面试题总结01-Spring和StringBuilder、StringBuffer的区别

常见面试题总结01【自我总结复习+学习自用】 一.String和StringBuilder、StringBuffer的区别 1.String 观察String源码: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private fin

ChangBai_zql的博客 991

Java中StringBuffer和StringBuilder的区别

StringBuilder和StringBuffer这两者都是可变的字符序列 参考文档 尽管如此。做题的时候,还是搞不清使用场景是什么,害 我们先来看源码: StringBuilder类 StringBuffer类 我们看上面的源码,都会发现它继承了一个抽象类AbstractStringBuilder 1、线程安全的角度: StringBuffer:线程安全 StringBuff...

qq_44723296的博客 501

Java进阶之深入理解String/StringBuffer与StringBuilder

1 String、StringBuffer与StringBuilder区别 (1)区别 String内容不可变,StringBuffer和StringBuilder内容可变; StringBuilder非线程安全(单线程使用),String与StringBuffer线程安全(多线程使用); 如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。 (2)...

chenliguan的博客 1万+

从Java源码角度彻底理解String,StringBuilder和StringBuffer的区别

字符串,就是一系列字符的集合。 Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串,其中StringBuilder类是到jdk 1.5才新增的。字符串操作可以说是几乎每门编程语言中所必不可少的,你真的理解其内幕吗? 下面让我们开始探秘之旅吧! 1、既然都是用来封装字符串的,那为什么还要3个类来封装呢? 2、它们三者之间到底

程序猿开发日志【学习永无止境】 9030

String、StringBuffer、StringBuilder区别,从源码角度分析内部机制

Stirng: 字符串常量,内部使用final进行修饰,所以一旦初始化后就不可更改,每一次的改变其实都是创建一个新的对象并对其重新赋值。 源码: public final class String implements java.io.Serializable, Comparable<String>, CharSequence 它实现了Serializable接口表示支...

记录网络缺失的知识 272
上一篇: SpringMVC面试题:什么是Servlet?
下一篇: Java NIO ByteBuffer 的使用与源码研究
程序员杨过
博客等级 码龄7年 13粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值