诡异的字符串问题。。。

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

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


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


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


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


image.png


就发展历史而言,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 而引起的。引起该问题的代码如下,见下图。


image.png


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


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


image.png

image.png

image.png

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


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


案例 2


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


开发环境:JDK 1.8


工具:Eclipse MyEclipse IDEA


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


image.png


在红线处,打上断点。


image.png


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


image.png


image.png 

image.png


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


image.png


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


image.png


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


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


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


参考

http://www.blogjava.net/xylz/archive/2012/03/15/371966.html

https://stackoverflow.com/questions/51814522/run-and-debug-have-different-results-in-method-named-append-in-stringbuffer

目录
打赏
0
0
0
0
1
分享
相关文章
|
10月前
1006 换个格式输出整数
1006 换个格式输出整数
51 0
根据正则表达式截取字串符,这个办法打败99%程序员
作为一名程序员,常常会在以下情况下使用函数功能根据正则表达式截取字符串:
uniapp一秒钟去除字符串的最后一个字符
如果在使用该字符串的过程中想要去掉它的最后一个字符,可以通过slice和substring来截取部分字符串,并返回一个新的字符串
243 0
java 中输入字符的方法(顺便判断元音辅音)
java 中输入字符的方法(顺便判断元音辅音)
147 0
今天同事问我,如何将一串字符串中的数字取出来,此时不用正则表达式,更待何时。。。(Unity3D)
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。 许多程序设计语言都支持利用正则表达式进行字符串操作。 例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。
面试官:请说出4种不使用第三方变量交换两个变量值的方法
面试官:请说出4种不使用第三方变量交换两个变量值的方法
170 0
面试官:请说出4种不使用第三方变量交换两个变量值的方法
【Unity3D 灵巧小知识点】 ☀️ | 字符串截取,截取某个路径字符串中 末尾文件 的名字
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。
Phper 学 C 兴趣入门 -为什么有时候字符串的处理这么难
Phper 学 C 兴趣入门 -为什么有时候字符串的处理这么难
430 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等