由一个bug引出java包装类型
工作中遇到过一个bug,用两个POJO的 Integer 字段 做 == 判断,明明“数值”相等结果返回 false。检查代码,调试,看源码搞了好久,才知道是Java包装类理解不够惹的祸。
为了弄清楚其中的本质,先上一段代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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));
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110758600-316203531.png)
分析运行结果:测试1说明,一个“数值”与Integer 做==判断,Integer对象会进行自动拆箱然后再进行判断。测试2、3说明,b、c、d 这三个对象内存地址一样,其实是同一个对象。 测试4说明,b 与 e不是同一个对象,且两个 Integer 做 == 判断时不会进行自动拆箱操作。
进一步查看编译后的代码:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110759756-342099233.png)
发现 其实 b、c、d 都是通过 Integer.valueOf()方法创建的。a、b 比较时进行了拆箱操作。
更进一步查看Integer类的源代码:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110800272-150804648.png)
哦,原来是Integer内部维护一个对象池,默认值的范围 [-128,127]。(可以通过修改 -XX:AutoBoxCacheMax=<size> 设置缓存的大小,值的范围 [-128,x],low 参数不可修改)。
接来对比一下 new Integer()方法:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110800772-2120600858.png)
直接创建,难怪b 与 e 不是同一个对象。
Java 有八种基本类型,相应的就有八种包装类。既然Integer有缓存,那么其他类型有没有呢?还是来查看源码吧。(JDK版本 1.8.0_05)
Long:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110801162-1641671444.png)
Short:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110801772-1432580323.png)
Byte:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110802178-854787555.png)
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110802553-1399312710.png)
Float:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110803194-1101255756.png)
Double:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110803709-603374375.png)
Boolean:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110804006-1635851690.png)
Character:
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110804350-964032322.png)
![](https://images2015.cnblogs.com/blog/775480/201704/775480-20170428110806428-66298552.png)
Java的八个包装类,除Float,Double 外其他六个类都在内部维护一个对象池,像上面直接在代码中赋值,编译器后实际上是调用 valueOf(),先去缓存中查找,没有才会创建,减少对象的创建。包装类的对象与基本类型比较会自动拆箱,而对方也是同一个包装类的对象则和普通对象一样。
分析这些有什么用呢?在Java中数据很多情况下用的是包装类型,当要进行比较时两方都是包装类,就会有可能得到诸如“为什么明明两个值一样就是不相等呢?”这样的结果。其他人怎么做我不知道,但是从上一次bug以后,代码中出现包装类比较,只要一方不是基本类型我就把包装拆箱。