• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

诡异的字符串问题。。。

技术杂谈 勤劳的小蚂蚁 3个月前 (01-24) 84次浏览 已收录 0个评论 扫描二维码

说问题前,我先跟各位读者聊一下字符串这个话题,谈起字符串也就离不开数据结构。

那问题来了,什么是数据结构呢?我之前也想过怎么优雅的来回答这个问题,每次总感觉自己给出的答案不够准确。于是我便请教了「木马之王」—— Chigo,他的回答很精炼,说出了我想要表达的意思,「数据结构就是结构化的数据模型,方便计算机存储和构造数据,比如字符串、数组、List、Set、Map、Class 、树、图等」,以后别人面试你的时候,你可以用得上^_^。

对于 Java 而言,它不仅提供八种内置基本数据类型,还提供了很多丰富的拓展数据类型,之所以要提供这么多的数据类型,就是便于我们这些懒惰的程序员使用「如果你想成为一名优秀的工程师,还是值得花时间去研究这些数据结构类型的」。

好了,言归正传,今天就来聊一下 String、StringBuffer 和 StringBuilder 这三个字符串处理类。

这三个类,我相信大大小小的面试基本上都会问。今天咱们不聊面试,只来排雷。


就发展历史而言,StringBuilder 都晚于它的两个老大哥,它是在 JDK 5 中才出现的,网上很多文章都说它与 StringBuffer 没得什么区别只是去掉了 sychronized 关键字「线程安全」部分。

其实对于 JDK 7 及之前的版本可以这么说,但是对于 JDK 8 以后,StringBuffer 是加了 toStringCache 缓存字段的,而且这个字段是用 transient 关键字修饰的,肯定有些读者不知道这个关键字是干嘛的,如果你用过一些序列化的工具,一定对这个关键字不会陌生,被这个关键字修饰过的属性,是不会被序列化的,换句话来说,就是这个字段只会存在于内存之中。

总的来说,JDK 8 之后 StringBuffer 还是有一点儿改变的,后面我们详细来谈谈它具体的改变。对于它们而言,都继承自 AbstractStringBuilder,其实说白了,StringBuffer 和 StringBuilder 的具体操作都是由 AbstractStringBuilder 来实现的,重点看一下它内部是如何扩容的。

对于 String 而言,我觉得是很基础而有特别重要的类,说得难听点,你只要还想吃 Java 这口饭,这个类你必须要掌握。它可聊的话题就太多了,比如它的不可变性?JDK 6 为什么不推荐使用它的 intern() 方法?它到底是值类型还是引用类型?JDK 8 之后,常量池有那些变化?各个版本的 JDK 在编译期间对它进行那些优化?JDK 9 以后存储数据的 char 数组发生了那些改变? 云云。。。

案例 1

我之前在网上看到一个案例,特别具有代表性,在这里给各位读者分享一下。

线上服务器负载过高而导致系统报警。

一般来说,负载过高,多半是某个程序在不停的消耗 CPU 而引起的。引起该问题的代码如下,见下图。


如果你根据堆栈信息进行分析,就会发现 CPU 在不停的执行拷贝动作,是什么原因导致的呢?

如果你熟悉 StringBuffer 的话,那么很快可以定位到,是 buf.toString() 导致的。有的读者可能会问你怎么知道呢?看一下它的源码不就知道了嘛。。。

注意到没,System.arraycopy() 这个函数就是问题症结,这是一个内存拷贝函数,直接操作系统内存。

问题找到了,那么也就可以抓药了,对于这类的问题,说白了还是开发者自己重复制造轮子所致,其实这也是我一直在团队强调的,有好的轮子就不要自己去制造,编码规范一定要统一起来。

案例 2

可能有读者朋友知道,我最近建了一个技术交流群,群里主要讨论技术,也会不时的有老司机开车「记得系好安全带」。这不,一个同学发现关于 IDEA 的调试问题,目前这个问题,我们还没有找到具体的症结,感兴趣的朋友一起研究一下。

开发环境:JDK 1.8

工具:Eclipse MyEclipse IDEA

具体描述:在如下的代码中,跟下图一样打上断点,注意一定要跟进 StringBuffer 源码里面,在 Eclipse 和 MyEclipse 能按照预期结果返回,但是 IDEA 中却不能正常返回。


在红线处,打上断点。


点击红圈,跟进到 StringBuffer 源码「如果你细心的话,一定注意到 append 方法跟 1.7 有所不同」,出现如下图所示。

 

你会发现 toStringCache 的值未被置 null,因此,导致还是去返回缓存里面的值,最终结果为「111」,而非「111222」,见下图。


但是,在 Eclipse 中,toStringCache 的值被置 null 了,见下图。


这个问题,我觉得还是挺有意思的,我初步怀疑可能是 IDEA 的问题,但是如果 IDEA 不设置断点,返回结果就跟预期的一样「111222」。

如果你找到了原因,欢迎留言告诉我~~~

今天的分享就到这里了,写一篇文章挺费时间的,希望各位读者转发一下,忆蓉君在此谢谢各位了。

参考


丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:诡异的字符串问题。。。
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00