string数组添加元素_一次关于String,String Builder,String Buffer 的面试经历,好险!

88616bd6c0650ad3f86ed4c3887a02c0.gif

前言
String,StringBuilder,StringBuffer的区别是啥?这个面试题估计每个程序员都应该碰到过吧。依稀记得第一次面试的时候,面试官问我这个问题时,心想着这不是很简单吗。深入了解这个问题后,发现这里面并不简单,面试官的套路还是深啊!

0afb03d205edec93f92790e1585e74a9.png

基础问答 面试官:你好,欢迎来面试,介绍一下自己吧。
你好,我是**, 来自 **,毕业于拖拉机学院,目前工作了2年,在 ** 公司做了一年的开发,做过的项目有。。。布拉布拉 然后双方对项目进行深入的讨论。。。 面试官:为什么我们建议在定义HashMap的时候,就指定它的初始化大小呢? 答:在当我们对HashMap初始化时,如果没有为其设置初始化容量,那么系统会默认创建一个容量为16的大小的集合。当我们向HashMap中添加元素时,如果HashMap的容量值超过了它的临界值(默认16*0.75=12)时,(0.75是HashMap的加载因子)HashMap将会重新扩容到下一个2的指数次幂(2^4=16 下一个2的指数次幂是2^5=32)。由于HashMap扩容要进行resize的操作,频繁的resize,会导致HashMap的性能下降,所以建议在确定HashMap集合的大小的情况下,指定其初始化大小,避免做过多的resize操作,导致性能下降。 面试官:那么HashMap什么时候进行扩容呢? 答:当我们不断的向HashMap中添加元素时,它会判断HashMap当前的容量值(当前元素的个数)是否超过了它的临界值(在没有指定其初始化大小时,默认16*0.75=12),如果添加的元素个数超过了临界值,它就会开始进行扩容。 面试官:HashMap在扩容时,扩容到多大? 答:HashMap在扩容时,它会扩容到下一个2的指数次幂,即当前容量的2倍,比如当前容量是24=16,将会扩容到下一个2的指数次幂25=32. 面试官:你能说一下为什么说HashMap是线程不安全的吗? 答:HashMap在多线程并发时线程不安全,主要表现在下面两个方面: (1) 当向HashMap中put(添加)元素时导致的多线程数据不一致 比如有两个线程 A 和 B ,首先 A 希望插入一个 key-value键值对到HashMap 中,它首先计算记录所要落到的 hash 桶的索引坐标,然后获取到该桶里面的链表头结点,此时线程 A 的时间片用完了,而此时线程 B 被调度得以执行,和线程 A 一样执行,只不过线程 B 成功将记录插到了桶里面。假设线程 A 插入的记录计算出来的 hash 桶索引和线程 B 要插入的记录计算出来的 hash 桶索引是一样的,那么当线程 B 成功插入之后,线程 A 再次被调度运行时,它依然持有过期的链表头但是它对此一无所知,以至于它认为它应该这样做,如此一来就覆盖了线程 B 插入的记录,这样线程 B 插入的记录就凭空消失了,造成了数据不一致的行为。 简单来说就是在多线程环境下,向HashMap集合中添加元素会存在覆盖的现象,导致了线程不安全。 (2) 当HashMap进行扩容调用resize()函数时引起死循环 HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容数组中,在多线程的环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现同时在同一数组下用链表表示,造成闭环,导致在get时会出现死循环,所以HashMap是线程不安全的。 HashMap的线程不安全主要体现在下面两个方面: 1.在JDK1.7中,当并发执行扩容操作时会造成环形链和数据丢失的情况。 2.在JDK1.8中,在并发执行put操作时会发生数据覆盖的情况。 面试官:那你能说一下String,StringBuilder,StringBuffer到底有什么区别吗? 答:String的值是不可改变的,这就导致每次对String的操作都会生成新的String对象,不禁效率底下, 而且浪费大量的内存空间;StringBuilder是可变类,任何对他指向的字符串的操作都不会产生新的对 象,但线程不安全;StringBuffer底层方法使用了synchronized关键字,线程比较安全,但效率 较StringBuilder慢; 面试官:String类它可以被继承吗? 答:不可以,因为String类使用final关键字进行修饰,所以不能被继承,并且StringBuilder,StringBuffer也是如此都被final关键字修饰。 面试官:为什么String的是不可变的? 答:因为存储数据的char数组是使用final进行修饰的,所以不可变。

92bbf5b0164dab1de1b89d6dfe7cff8d.png

面试官:为什么String Buffer是线程安全的? 答:这是因为在StringBuffer类内,常用的方法都使用了synchronized 进行同步所以是线程安全的,然而StringBuilder并没有。这也就是运行速度StringBuilder > StringBuffer的原因了。 面试官:刚才你说到了synchronized关键字 ,那能讲讲synchronized的表现形式嘛? 答:
  • 对于静态同步方法,锁是当前类的class对象。
  • 对于普通同步方法 ,锁是当前实例对象。
  • 对于同步方法块,锁是Synchonized括号配置的对象。
面试官:能讲讲synchronized的原理嘛? 答:synchronized是一个重量级锁,实现依赖于JVM 的 monitor 监视器锁。主要使用monitorenter和monitorexit指令来实现方法同步和代码块同步。在编译的是时候,会将monitorexit指令插入到同步代码块的开始位置,而monitorexit插入方法结束处和异常处,并且每一个monitorexit都有一个与之对应的monitorexit。 任何对象都有一个monitor与之关联,当一个monitor被持有后,它将被处于锁定状态,线程执行到monitorenter指令时间,会尝试获取对象所对应的monitor的所有权,即获取获得对象的锁,由于在编译期会将monitorexit插入到方法结束处和异常处,所以在方法执行完毕或者出现异常的情况会自动释放锁。 面试官:
(内心OS:竟然没问倒他,让他回去等通知吧 ) 你的水平我这边基本了解了,我对你还是比较满意的,但是我们这边还有几个候选人还没面试,没办法直接给你答复,你先回去等通知吧。
我:好的好的,谢谢面试官,我这边先回去了。
(内心OS:好险好险,一个string差点被问倒,幸好面试前好好看了一下,不然今天就是面试惨案了)
本文链接:https://blog.csdn.net/qq_50524970/article/details/109189595 作者:不划水的可乐

61a631fe058054e041697108ad516fac.png

1f2def670684795bbe78ede634972ae0.png f430bc0886a244bb24413f9878f58904.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值