由一个bug引出java包装类型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了由一个bug引出java包装类型相关的知识,希望对你有一定的参考价值。

       工作中遇到过一个bug,用两个POJO的 Integer 字段 做 == 判断,明明“数值”相等结果返回 false。检查代码,调试,看源码搞了好久,才知道是Java包装类理解不够惹的祸。 

为了弄清楚其中的本质,先上一段代码:
技术分享
 1         int a = 5;
 2         Integer b = 5;
 3         Integer c = Integer.valueOf(5);
 4         Integer d = Integer.valueOf(5);
 5         Integer e = new Integer(5);
 6         
 7         System.out.println("测试1,a == b 的结果:" + (a == b));
 8         System.out.println("测试2,b == c 的结果:" + (b == c));
 9         System.out.println("测试3,c == d 的结果:" + (c == d));
10         System.out.println("测试4,d == e 的结果:" + (d == e));
11         System.out.println("测试5,b == e 的结果:" + (b == e));
View Code

 

技术分享
分析运行结果:测试1说明,一个“数值”与Integer 做==判断,Integer对象会进行自动拆箱然后再进行判断。测试2、3说明,b、c、d 这三个对象内存地址一样,其实是同一个对象。  测试4说明,b 与 e不是同一个对象,且两个 Integer 做 == 判断时不会进行自动拆箱操作。
进一步查看编译后的代码:
技术分享
 发现 其实 b、c、d 都是通过 Integer.valueOf()方法创建的。a、b 比较时进行了拆箱操作。
更进一步查看Integer类的源代码:
技术分享
 哦,原来是Integer内部维护一个对象池,默认值的范围 [-128,127]。(可以通过修改 -XX:AutoBoxCacheMax=<size> 设置缓存的大小,值的范围 [-128,x],low 参数不可修改)。
接来对比一下 new Integer()方法:
技术分享
 直接创建,难怪b 与 e 不是同一个对象。
 
        Java 有八种基本类型,相应的就有八种包装类。既然Integer有缓存,那么其他类型有没有呢?还是来查看源码吧。(JDK版本 1.8.0_05)
 
Long:
技术分享
 
Short:
技术分享

 Byte:
技术分享
 技术分享

 Float:
技术分享
 
 
Double:
技术分享
 
Boolean:
技术分享
 
Character:
技术分享
 技术分享
   Java的八个包装类,除Float,Double 外其他六个类都在内部维护一个对象池,像上面直接在代码中赋值,编译器后实际上是调用 valueOf(),先去缓存中查找,没有才会创建,减少对象的创建。包装类的对象与基本类型比较会自动拆箱,而对方也是同一个包装类的对象则和普通对象一样。
  分析这些有什么用呢?在Java中数据很多情况下用的是包装类型,当要进行比较时两方都是包装类,就会有可能得到诸如“为什么明明两个值一样就是不相等呢?”这样的结果。其他人怎么做我不知道,但是从上一次bug以后,代码中出现包装类比较,只要一方不是基本类型我就把包装拆箱。
 


以上是关于由一个bug引出java包装类型的主要内容,如果未能解决你的问题,请参考以下文章

由BigDecimal类型的数据引出的问题分析

包装类

Java包装类之实体类不要使用基本类型

升级SpringBoot版本,引出了一个大Bug

由forEach中return无法终止函数执行引出的探究

一个小BUG,引出对Linux启动机制Systemd的代码分析