Leader:这样的 Bug 你也写的出来???
2020/1/28 17:26:37
本文主要是介绍Leader:这样的 Bug 你也写的出来???,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Hello~各位读者新年好!不知道大家春节假期是否已延长,小黑哥刚接到通知,假期延长到 2 月 2 号,另外回去之后需要在家办公,自行隔离两周。还没试过在家办公,小黑哥就怕到时候生物钟还没调整过来,一觉睡醒已经是下午了。。。
![](/upload/202001/28/202001281726366938.png)
前言
春节假期,还躺在床上小黑哥,收到对账系统的一条预警短信,提示当前系统资金核对存在问题。关于资金的问题,都是大问题,小黑哥连忙拔出电脑,连上 VPN,登录生产环境的查看相关日志。
通过日志,很快小黑哥定位到相关代码。
![](/upload/202001/28/202001281726367084.png)
有的同学可能一下子就能看出这里的问题, Long
对象采用 !=
进行比较,这真是一个低级 Bug
。幸好 Leader 还不知道,赶紧悄悄修复一下。
![](/upload/202001/28/202001281726367172.png)
现在回想小黑哥当初写这段代码的时候,误以为两个 Long
对象比较将会进行自动拆箱,转变为两个基本数值类型比较。
下面开始复习一下 Java
自动装箱与拆箱机制。
自动装箱与拆箱机制
自动装箱(Autoboxing),是 JDK5
新增的一种语法糖,将会在代码编译时自动将原始类型转换为其对应的对象包装器类。例如将 int
转换为 Integer
,double
转换为 Double
。如果转换结果相反,我们就将其称为拆箱。
下面是一个自动装箱的例子:
![](/upload/202001/28/202001281726367270.png)
上面代码 li.add(i)
就发生自动装箱,将基本数据类型 long
转换为其包装类 Long
。
查看这段代码对应的字节码。
![](/upload/202001/28/202001281726367543.png)
图上黄线标注的字节码对应的代码为 li.add(i)
。从这我们可以看到 long
类型的自动装箱实际上调用 Long#valueOf
方法。所以编译器运行时将之前的代码转换为下面的代码
![](/upload/202001/28/202001281726367709.png)
接下来我们来看一个自动拆箱的例子:
![](/upload/202001/28/202001281726367875.png)
由于 Long
包装类对象不能用于求模(%
)以及 +=
,所以这段代码将会发生自动拆箱,将 Long
转化为 long
类型。相应的这里我们也看下其编译之后的字节码。
![](/upload/202001/28/202001281726368246.png)
这里的字节码比之前的复杂很多,这里主要关注黄线部分。可以看到这里调用 Long#longValue
将 Long
对象转为 long
类型。所以自动拆箱这个例子,最后编译器生成字节码等同于以下代码:
![](/upload/202001/28/202001281726368461.png)
Java
规定的 8 种数据类型都有其对应包装类,这些都可以进行相应的自动装箱和拆箱。
![](/upload/202001/28/202001281726368617.png)
这里小结一下:
- 自动装箱机制是通过调用包装器类
valueOf
实现 - 自动拆箱机制通过调用包装器类的相应的
**Value
,如longValue
,intValue
实现
Cache 陷阱
自动装箱和拆箱概念说起其实挺简单的,但是如果使用不当可能就会踩坑。
我们来看一段代码:
![](/upload/202001/28/202001281726368813.png)
如果你对上面的结果的不是很清楚,恭喜你,暖男小黑哥帮你排雷了。
上面输出结果为:
true false 复制代码
这里输出结果之所以为这样,主要与 LongCache
有关。自动装箱进制将会调用 Long#valueOf
,其源码如下:
![](/upload/202001/28/202001281726368979.png)
只要数值范围位于 [-128,127] 之间,valueOf
就会返回 LongCache.cache
这个数组中的值。所以 aLong/bLong
其实是同一个对象,cLong/dLong
是两个不用对象的。
Long#valueOf
这个方法通过 Cache
减少创建对象的数量,提高相应的空间以及时间性能。
![](/upload/202001/28/202001281726369155.png)
至于为什么缓存 [-128,127] 之间的数字,而没有缓存更多的值,甚至缓存所有的值?
这是因为 Long
范围为**[-2^63,2^63]**,总共 2^64 ,这么多对象实例,显然不宜全部缓存。至于 [-128,127] 之间数字 JDK
设计者认为这些数字使用频率高,个人认为这是一个经验值。
另外这个 cache
可能会导致另外一个问题:锁共用。
![](/upload/202001/28/202001281726369311.png)
上面代码看起来 A
类使用 along
这个对象锁,而 B
类使用 blong
这个对象锁,看起来两个风马牛不相及,但是实际上两个对象由于 Cache
机制,导致其实际上使用同一个对象,A
与 B
共用同一把锁。
除了 Long#valueOf
方法中存在 Cache
以外,Byte
,Short
,Integer
,Character
也存在相应的 Cache
值。其中 Integer
对象可以通过 -XX:AutoBoxCacheMax=<size>
改变 Cache
初始范围。
技术总结
通过自动装箱与拆箱机制,大大减少了数据类型转化的代码,但是同时带来一些隐藏的问题。这里我们需要记住:
- 所有对象之间不能使用
==
比较,需要使用equals
代替,推荐使用JDK7
提供的Objects#equals
方法,该方法可以有效避免比较过程空指针问题 - 基本数据类型的包装类不适合当做锁对象
各位读者朋友们,请牢记这两个总结,不要踩中这两个坑哦。另外推荐大家安装一下 FindBugs
这个插件,通过这个插件扫描代码,可以找出代码中的相关缺陷。上面两个问题,通过 FindBugs
都能扫描出来,简直神器。
对象比较问题:
![](/upload/202001/28/202001281726369682.png)
锁问题
![](/upload/202001/28/202001281726369985.png)
帮助文档
- Autoboxing and Unboxing『https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html』
- 极客时间-『Java并发编程实战』专栏
欢迎关注我的公众号:程序通事,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:studyidea.cn
![](/upload/202001/28/202001281726370375.png)
这篇关于Leader:这样的 Bug 你也写的出来???的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)
- 2024-05-31全网首发!软考2024年5月《软件设计师》真题+解析+答案!(21-30题)
- 2024-05-30【Java】百万数据excel导出功能如何实现
- 2024-05-30我们小公司,哪像华为一样,用得上IPD(集成产品开发)?