Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >由String,String Builder,String Buffer 引起的面试惨案

由String,String Builder,String Buffer 引起的面试惨案

原创
作者头像
不一样的科技宅
修改于 2020-09-02 06:41:58
修改于 2020-09-02 06:41:58
8520
举报
pexels-pixabay-60504
pexels-pixabay-60504

前言

  String,StringBuilder,StringBuffer的区别是啥?这个面试题估计每个JAVA都应该碰到过吧。依稀记得第一次面试的时候,面试官问我这个问题时,心想着能有啥区别不都是拼接字符串嘛。深入了解这个问题后,发现并不简单?

前菜

面试官:你好,你是不一样的科技宅是吧?

小宅:面试官你好,我是不一样的科技宅。

面试官:你好,麻烦做一个简单的自我介绍吧。

小宅:我叫不一样的科技宅,来自xxx,做过的项目主要有xxxx用到xxx,xxx技术。

20180719930824_lrEKIh
20180719930824_lrEKIh

面试官:好的,对你的的履历有些基本了解了,那我们先聊点基础知识吧。

小宅:内心OS(放马过来吧)

开胃小菜

面试官:String,StringBuilder,StringBuffer的区别是啥?

小宅:这个太简单了吧,这是看不起我?

  • 从可变性来讲String的是不可变的,StringBuilder,StringBuffer的长度是可变的。
  • 从运行速度上来讲StringBuilder > StringBuffer > String。
  • 从线程安全上来StringBuilder是线程不安全的,而StringBuffer是线程安全的。

  所以 String:适用于少量的字符串操作的情况,StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况,StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况。

75f3cd331b7ab4ca4552847a746952da
75f3cd331b7ab4ca4552847a746952da
面试官:为什么String的是不可变的?

小宅:因为存储数据的char数组是使用final进行修饰的,所以不可变。

image-20200714151350294
image-20200714151350294
面试官:刚才说到String是不可变,但是下面的代码运行完,却发生变化了,这是为啥呢?
代码语言:txt
AI代码解释
复制
public class Demo {

    public static void main(String[] args) {
        String str = "不一样的";
        str = str + "科技宅";
        System.out.println(str);
    }

}

很明显上面运行的结果是:不一样的科技宅

我们先使用javac Demo.class 进行编译,然后反编译javap -verbose Demo 得到如下结果:

代码语言:txt
AI代码解释
复制
 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: ldc           #2                  // String 不一样的
         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:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        14: ldc           #6                  // String 科技宅
        16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: astore_1
        23: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        26: aload_1
        27: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        30: return

  我们可以发现,在使用+ 进行拼接的时候,实际上jvm是初始化了一个StringBuilder进行拼接的。相当于编译后的代码如下:

代码语言:txt
AI代码解释
复制
public class Demo {

    public static void main(String[] args) {
        String str = "不一样的";
        StringBuilder builder =new StringBuilder();
        builder.append(str);
        builder.append("科技宅");
        str = builder.toString();
        System.out.println(str);
    }

}

我们可以看下builder.toString(); 的实现。

代码语言:txt
AI代码解释
复制
@Override
public String toString() {
  // Create a copy, don't share the array
  return new String(value, 0, count);
}

  很明显toString方法是生成了一个新的String对象而不是更改旧的str的内容,相当于把旧str的引用指向的新的String对象。这也就是str发生变化的原因。

分享我碰到过的一道面试题,大家可以猜猜答案是啥?文末有解析哦

代码语言:txt
AI代码解释
复制
public class Demo {

    public static void main(String[] args) {
        String str = null;
        str = str + "";
        System.out.println(str);
    }

}
面试官:String类可以被继承嘛?

小宅:不可以,因为String类使用final关键字进行修饰,所以不能被继承,并且StringBuilder,StringBuffer也是如此都被final关键字修饰。

面试官:为什么String Buffer是线程安全的?

小宅:这是因为在StringBuffer类内,常用的方法都使用了synchronized 进行同步所以是线程安全的,然而StringBuilder并没有。这也就是运行速度StringBuilder > StringBuffer的原因了。

20181119593911_rYDslC
20181119593911_rYDslC
面试官:刚才你说到了synchronized关键字 ,那能讲讲synchronized的表现形式嘛?

小宅

  • 对于普通同步方法 ,锁是当前实例对象。
  • 对于静态同步方法,锁是当前类的class对象。
  • 对于同步方法块,锁是Synchonized括号配置的对象。
面试官:能讲讲synchronized的原理嘛?

小宅synchronized是一个重量级锁,实现依赖于JVMmonitor 监视器锁。主要使用monitorentermonitorexit指令来实现方法同步和代码块同步。在编译的是时候,会将monitorexit指令插入到同步代码块的开始位置,而monitorexit插入方法结束处和异常处,并且每一个monitorexit都有一个与之对应的monitorexit

  任何对象都有一个monitor与之关联,当一个monitor被持有后,它将被处于锁定状态,线程执行到monitorenter指令时间,会尝试获取对象所对应的monitor的所有权,即获取获得对象的锁,由于在编译期会将monitorexit插入到方法结束处和异常处,所以在方法执行完毕或者出现异常的情况会自动释放锁。

硬菜来了

面试官:前面你提到synchronized是个重量级锁,那它的优化有了解嘛?
006qir4oly1g0qzhmov3tj30gw0cgjte
006qir4oly1g0qzhmov3tj30gw0cgjte

小宅:为了减少获得锁和和释放锁带来的性能损耗引入了偏向锁、轻量级锁、重量级锁来进行优化,锁升级的过程如下:

  首先是一个无锁的状态,当线程进入同步代码块的时候,会检查对象头内和栈帧中的锁记录里是否存入存入当前线程的ID,如果没有使用CAS 进行替换。以后该线程进入和退出同步代码块不需要进行CAS 操作来加锁和解锁,只需要判断对象头的Mark word内是否存储指向当前线程的偏向锁。如果有表示已经获得锁,如果没有或者不是,则需要使用CAS进行替换,如果设置成功则当前线程持有偏向锁,反之将偏向锁进行撤销并升级为轻量级锁。

  轻量级锁加锁过程,线程在执行同步块之前,JVM会在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头的Mark Word复制到锁记录(Displaced Mark Word)中,然后线程尝试使用CAS 将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,反之表示其他线程竞争锁,当前线程便尝试使用自旋来获得锁。

  轻量级锁解锁过程,解锁时,会使用CAS将Displaced Mark Word替换回到对象头,如果成功,则表示竞争没有发生,反之则表示当前锁存在竞争锁就会膨胀成重量级锁。

升级过程流程图

533411-20200423173203871-980115964
533411-20200423173203871-980115964

白话一下:

  可能上面的升级过程和升级过程图,有点难理解并且还有点绕。我们先可以了解下为什么会有锁升级这个过程?HotSpot的作者经过研究发现,大多数情况下锁不仅不存在多线程竞争,而且总是由同一个线程多次获得。为了避免获得锁和和释放锁带来的性能损耗引入锁升级这样一个过程。理解锁升级这个流程需要明确一个点:发生了竞争才锁会进行升级并且不能降级。

  我们以两个线程T1,T2执行同步代码块来演示锁是如何膨胀起来的。我们从无锁的状态开始 ,这个时候T1进入了同步代码块,判断当前锁的一个状态。发现是一个无锁的状态,这个时候会使用CAS将锁记录内的线程Id指向T1并从无锁状态变成了偏向锁。运行了一段时间后T2进入了同步代码块,发现已经是偏向锁了,于是尝试使用CAS去尝试将锁记录内的线程Id改为T2,如果更改成功则T2持有偏向锁。失败了说明存在竞争就升级为轻量级锁了。

  可能你会有疑问,为啥会失败呢?我们要从CAS操作入手,CAS是Compare-and-swap(比较与替换)的简写,是一种有名的无锁算法。CAS需要有3个操作数,内存地址V,旧的预期值A,即将要更新的目标值B,换句话说就是,内存地址0x01存的是数字6我想把他变成7。这个时候我先拿到0x01的值是6,然后再一次获取0x01的值并判断是不是6,如果是就更新为7,如果不是就再来一遍之道成功为止。这个主要是由于CPU的时间片原因,可能执行到一半被挂起了,然后别的线程把值给改了,这个时候程序就可能将错误的值设置进去,导致结果异常。

  简单了解了一下CAS现在让我们继续回到锁升级这个过程,T2尝试使用CAS进行替换锁记录内的线程ID,结果CAS失败了这也就意味着,这个时候T1抢走了原本属于T2的锁,很明显这一刻发生了竞争所以锁需要升级。在升级为轻量级锁前,持有偏向锁的线程T1会被暂停,并检查T1的状态,如果T1处于未活动的状态/已经退出同步代码块的时候,T1会释放偏向锁并被唤醒。如果未退出同步代码块,则这个时候会升级为轻量级锁,并且由T1获得锁,从安全点继续执行,执行完后对轻量级锁进行释放。

  偏向锁的使用了出现竞争了才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。并且偏向锁的撤销需要等待全局安全点(这个时间点没有任何正在执行的字节码)。

  T1由于没有人竞争经过一段时间的平稳运行,在某一个时间点时候T2进来了,产生使用CAS获得锁,但是发现失败了,这个时候T2会等待一下(自旋获得锁),由于竞争不是很激烈所以等T1执行完后,就能获取到锁并进行执行。如果长时间获取不到锁则就可能发生竞争了,可能出现了个T3把原本属于T2的轻量级锁给抢走了,这个时候就会升级成重量级锁了。

u=628528004,774370142&fm=26&gp=0
u=628528004,774370142&fm=26&gp=0

吃完撤退

面试官:内心OS:竟然没问倒他,看来让他培训是没啥希望了,让他回去等通知吧 。

  小宅是吧,你的水平我这边基本了解了,我对你还是比较满意的,但是我们这边还有几个候选人还没面试,没办法直接给你答复,你先回去等通知吧。

小宅:好的好的,谢谢面试官,我这边先回去了。多亏我准备的充分,全回答上来了,应该能收到offer了吧。

timg
timg

面试题解析

代码语言:txt
AI代码解释
复制
public class Demo {

    public static void main(String[] args) {
        String str = null;
        str = str + "";
        System.out.println(str);
    }

}

答案是 null,从之前我们了解到使用+进行拼接实际上是会转换为StringBuilder使用append方法进行拼接。所以我们看看append方法实现逻辑就明白了。

代码语言:txt
AI代码解释
复制
public AbstractStringBuilder append(String str) {
  if (str == null)
    return appendNull();
  int len = str.length();
  ensureCapacityInternal(count + len);
  str.getChars(0, len, value, count);
  count += len;
  return this;
}
代码语言:txt
AI代码解释
复制
private AbstractStringBuilder appendNull() {
  int c = count;
  ensureCapacityInternal(c + 4);
  final char[] value = this.value;
  value[c++] = 'n';
  value[c++] = 'u';
  value[c++] = 'l';
  value[c++] = 'l';
  count = c;
  return this;
}

从代码中可以发现,如果传入的字符串是null时,调用appendNull方法,而appendNull会返回null。

结尾

  我是不一样的科技宅,每天进步一点点,体验不一样的生活。我们下期见!

  如果觉得对你有帮助,可以多多评论,多多点赞哦,也可以到我的主页看看,说不定有你喜欢的文章,也可以随手点个关注哦,谢谢。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入探索:【人工智能】、【机器学习】与【深度学习】的全景视觉之旅
人工智能(Artificial Intelligence, AI)是计算机科学的一个分支,旨在开发能够模拟或增强人类智能的系统。AI的研究范围广泛,涵盖了从基础算法到复杂系统的开发。
小李很执着
2024/08/14
1390
【机器学习】机器学习重要方法——深度学习:理论、算法与实践
深度学习(Deep Learning)作为机器学习的一个重要分支,通过构建和训练多层神经网络,自动提取和学习数据的多层次特征,近年来在多个领域取得了突破性的进展。本文将深入探讨深度学习的基本原理、核心算法及其在实际中的应用,并提供代码示例以帮助读者更好地理解和掌握这一技术。
E绵绵
2025/05/25
1930
【机器学习】机器学习重要方法——深度学习:理论、算法与实践
从人类大脑到人工神经网络:神经网络的生物学启发
人工神经网络(ANN)是深度学习领域的核心技术之一,它模拟了人类大脑的基本神经结构,通过层次化的神经元连接进行信息处理和学习。自从1950年代人工神经网络的初步构思以来,随着计算能力的提升,神经网络已逐步发展成一个高度复杂的模型,广泛应用于图像识别、自然语言处理、语音识别等多个领域。然而,人工神经网络并非凭空产生,它深受人类大脑生物学结构的启发,特别是神经元的结构和信息传递方式。本文将深入探讨从人类大脑到人工神经网络的演化过程,并通过代码示例帮助理解神经网络模型的构建与应用。
一键难忘
2025/03/18
2720
深度学习入门指南:一篇文章全解
https://cloud.tencent.com/developer/article/2465232?shareByChannel=link
池央
2024/11/13
2100
深度学习入门指南:一篇文章全解
深度学习的原理与应用:开启智能时代的大门
深度学习(Deep Learning)是人工智能(AI)和机器学习(ML)领域中备受瞩目的一项技术。凭借其强大的数据处理能力和自我学习能力,深度学习在多个领域展现出了巨大的潜力和应用前景。本文将详细介绍深度学习的基本原理,并通过具体代码示例展示其在图像识别中的应用。
Echo_Wish
2024/12/26
1980
深度学习的原理与应用:开启智能时代的大门
使用 Python 实现的卷积神经网络初学者指南
卷积神经网络是一种专为处理图像和视频而设计的深度学习算法。它以图像为输入,提取和学习图像的特征,并根据学习到的特征进行分类。
磐创AI
2021/10/27
1.6K0
使用 Python 实现的卷积神经网络初学者指南
【人工智能】全景解析:【机器学习】【深度学习】从基础理论到应用前景的【深度探索】
无监督学习 是一种机器学习类型,模型在没有标注数据的情况下,通过识别数据中的模式和结构进行学习。
小李很执着
2024/08/14
2490
用Python探索人工智能:从线性回归到神经网络入门
人工智能(AI)正在改变世界,从推荐系统到自动驾驶,其应用无处不在。Python凭借丰富的库(如scikit-learn、TensorFlow)成为AI开发的首选语言。本文将带你从简单的线性回归入手,逐步过渡到神经网络,揭开AI的神秘面纱。无论你是AI新手还是想入门深度学习,这篇教程都能帮你迈出第一步。欢迎在评论区分享你的AI学习心得!
DevKevin
2025/03/09
2090
【机器学习】探索未来科技的前沿:人工智能、机器学习与大模型
随着科技的不断进步,人工智能(AI)、机器学习(ML)和大模型(Large Models)成为了现代计算机科学领域的核心技术。它们不仅推动了科学研究的进步,也在多个行业中掀起了革命性的变革。从自动驾驶汽车到智能语音助手,再到精准医疗和金融预测,这些技术的应用已经深入到我们日常生活的方方面面。本文将深入探讨这三大技术的基本概念、历史发展、实现原理及其在实际生活中的应用,旨在为读者提供一个全面而深入的了解。
E绵绵
2024/06/01
9020
[Python人工智能] 十九.Keras搭建循环神经网络分类案例及RNN原理详解
从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前一篇文章分享了卷积神经网络CNN原理,并通过Keras编写CNN实现了MNIST分类学习案例。这篇文章将详细讲解循环神经网络RNN的原理知识,并采用Keras实现手写数字识别的RNN分类案例及可视化呈现。基础性文章,希望对您有所帮助!
Eastmount
2022/11/25
1.1K0
使用Python实现深度学习模型:智能产品设计与开发
在智能产品设计与开发领域,深度学习模型的应用越来越广泛。本文将介绍如何使用Python构建一个简单的深度学习模型,并将其应用于智能产品的设计与开发。为了使内容尽可能通俗易懂,我们将以图像分类为例,详细讲解每一步骤。
Echo_Wish
2024/10/14
1760
使用Python实现深度学习模型:智能产品设计与开发
【深度智能】:迈向高级时代的人工智能全景指南
本学习路线详细分解了人工智能学习过程中涉及的各个知识点,并通过具体案例对其进行了深入解析。学习者应从基础知识入手,逐步深入到机器学习和深度学习领域,再到高级应用、项目实践和前沿研究,持续学习和实践,不断提升自己的能力。
小李很执着
2024/09/21
1430
【深度智能】:迈向高级时代的人工智能全景指南
我的第一次模型训练:从小白到入门的深度学习之旅
作为一个技术爱好者,我对深度学习一直抱有浓厚的兴趣。然而,当我第一次真正着手训练模型时,内心还是充满了忐忑。毕竟,训练一个模型听起来像是一件只有“大神”才敢尝试的事情。但经过一步步的实践,我不仅完成了任务,还从中收获了满满的成就感和经验。今天,我以Echo_Wish的身份,跟大家聊聊我的这次初体验,希望能给正在犹豫的小伙伴一些启发。
Echo_Wish
2025/04/12
660
我的第一次模型训练:从小白到入门的深度学习之旅
深入解析EfficientNet:高效深度学习网络与ResNet的对比(使用keras进行代码复现,并使用cifar10数据集进行实战)
在深度学习领域,卷积神经网络(CNN)是解决图像分类、目标检测等问题的关键技术之一。近年来,随着深度学习的不断发展,新的网络架构不断涌现。在众多网络架构中,EfficientNet和ResNet都成为了深度学习模型的佼佼者,分别在高效性和深度特性上得到了广泛应用。本文将详细介绍EfficientNet,并与经典的ResNet进行对比,分析它的架构、使用场景、适用问题及实例。
机器学习司猫白
2025/03/05
5300
深入解析EfficientNet:高效深度学习网络与ResNet的对比(使用keras进行代码复现,并使用cifar10数据集进行实战)
浅谈深度神经网络
神经网络 (neural network) 受到人脑的启发,可模仿生物神经元相互传递信号。神经网络就是由神经元组成的系统。如下图所示,神经元有许多树突 (dendrite) 用来输入,有一个轴突 (axon) 用来输出。它具有两个最主要的特性:兴奋性和传导性:
用户5753894
2023/09/02
3280
浅谈深度神经网络
人工智能中的深度学习:原理与实践
文章链接:https://cloud.tencent.com/developer/article/2474710
远方2.0
2024/12/08
2670
人工智能中的深度学习:原理与实践
人工智能在图像识别中的应用:从CNN到Transformers
图像识别是计算机视觉领域的一个重要任务,涵盖了从物体检测到面部识别等多种应用。随着深度学习技术的发展,特别是卷积神经网络(CNN)和自注意力机制(Transformers)的引入,图像识别任务的准确性和效率得到了显著提升。本篇文章将探讨人工智能在图像识别中的应用,重点分析从传统的CNN到现代Transformer模型的演进,并结合代码实例展示其应用。
一键难忘
2025/03/15
9440
智能新时代:探索【人工智能】、【机器学习】与【深度学习】的前沿技术与应用
前几天偶然发现了一个超棒的人工智能学习网站,内容通俗易懂,讲解风趣幽默,简直让人欲罢不能。忍不住分享给大家,点击这里立刻跳转,开启你的AI学习之旅吧! 前言 – 人工智能教程
小李很执着
2024/08/29
2160
智能新时代:探索【人工智能】、【机器学习】与【深度学习】的前沿技术与应用
Python人工智能 | 十八.Keras搭建卷积神经网络及CNN原理详解
从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前一篇文章详细讲解了Keras实现分类学习,以MNIST数字图片为例进行讲解。本篇文章详细讲解了卷积神经网络CNN原理,并通过Keras编写CNN实现了MNIST分类学习案例。基础性文章,希望对您有所帮助!
Eastmount
2022/11/25
1.6K0
从【人工智能】到【计算机视觉】,【深度学习】引领的未来科技创新与变革
本文旨在为读者提供一个全面的人工智能学习指南,涵盖从基础概念到高级技术的方方面面。我们将通过理论讲解、代码示例和应用场景分析,帮助读者深刻理解人工智能、机器学习、算法、深度学习和计算机视觉的基本原理和实际应用。
小李很执着
2024/08/20
4970
从【人工智能】到【计算机视觉】,【深度学习】引领的未来科技创新与变革
推荐阅读
深入探索:【人工智能】、【机器学习】与【深度学习】的全景视觉之旅
1390
【机器学习】机器学习重要方法——深度学习:理论、算法与实践
1930
从人类大脑到人工神经网络:神经网络的生物学启发
2720
深度学习入门指南:一篇文章全解
2100
深度学习的原理与应用:开启智能时代的大门
1980
使用 Python 实现的卷积神经网络初学者指南
1.6K0
【人工智能】全景解析:【机器学习】【深度学习】从基础理论到应用前景的【深度探索】
2490
用Python探索人工智能:从线性回归到神经网络入门
2090
【机器学习】探索未来科技的前沿:人工智能、机器学习与大模型
9020
[Python人工智能] 十九.Keras搭建循环神经网络分类案例及RNN原理详解
1.1K0
使用Python实现深度学习模型:智能产品设计与开发
1760
【深度智能】:迈向高级时代的人工智能全景指南
1430
我的第一次模型训练:从小白到入门的深度学习之旅
660
深入解析EfficientNet:高效深度学习网络与ResNet的对比(使用keras进行代码复现,并使用cifar10数据集进行实战)
5300
浅谈深度神经网络
3280
人工智能中的深度学习:原理与实践
2670
人工智能在图像识别中的应用:从CNN到Transformers
9440
智能新时代:探索【人工智能】、【机器学习】与【深度学习】的前沿技术与应用
2160
Python人工智能 | 十八.Keras搭建卷积神经网络及CNN原理详解
1.6K0
从【人工智能】到【计算机视觉】,【深度学习】引领的未来科技创新与变革
4970
相关推荐
深入探索:【人工智能】、【机器学习】与【深度学习】的全景视觉之旅
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档