经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Java-Integer好大一坑,一不小心就掉进去了
来源:cnblogs  作者:遛马少年  时间:2023/2/10 9:20:02  对本文有异议

遛马少年,一个代码写的很6的程序员,专注于技术干货分享

最近,在处理线上bug的时候,发现了一个奇怪的现象

业务代码大概是这样的

  1. public static boolean doSth(Integer x, Integer y) {
  2. if (x == y) {
  3. return true;
  4. }
  5. //do other...
  6. return false;
  7. }

当x、y都是较小的值时,比如100、100,正常返回true

当是较大值时,比如500、500,反而返回false

难道100==100,500!=500吗?

带着这样的疑问,我写了个demo程序一探究竟

  1. public class IntDemo {
  2. public static boolean doSth(Integer a, Integer b) {
  3. if (a == b) {
  4. return true;
  5. }
  6. return false;
  7. }
  8. public static void main(String[] args) {
  9. int a = 100;
  10. int b = 500;
  11. System.out.println(doSth(a, a));
  12. System.out.println(doSth(b, b));
  13. }
  14. }

输出结果为:

image.png

奇怪!底层是怎么处理的呢?我用javap看了一下上面代码的字节码指令

  1. public class com.integer.IntDemo {
  2. public com.integer.IntDemo();
  3. Code:
  4. 0: aload_0
  5. 1: invokespecial #1 // Method java/lang/Object."<init>":()V
  6. 4: return
  7. public static boolean doSth(java.lang.Integer, java.lang.Integer);
  8. Code:
  9. 0: aload_0
  10. 1: aload_1
  11. 2: if_acmpne 7
  12. 5: iconst_1
  13. 6: ireturn
  14. 7: iconst_0
  15. 8: ireturn
  16. public static void main(java.lang.String[]);
  17. Code:
  18. 0: bipush 100
  19. 2: istore_1
  20. 3: sipush 500
  21. 6: istore_2
  22. 7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
  23. 10: iload_1
  24. 11: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
  25. 14: iload_1
  26. 15: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
  27. 18: invokestatic #4 // Method doSth:(Ljava/lang/Integer;Ljava/lang/Integer;)Z
  28. 21: invokevirtual #5 // Method java/io/PrintStream.println:(Z)V
  29. 24: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
  30. 27: iload_2
  31. 28: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
  32. 31: iload_2
  33. 32: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
  34. 35: invokestatic #4 // Method doSth:(Ljava/lang/Integer;Ljava/lang/Integer;)Z
  35. 38: invokevirtual #5 // Method java/io/PrintStream.println:(Z)V
  36. 41: return
  37. }

可以看到,doSth函数传入的实参是int类型,函数定义的形参却是Integer类型

看到第11行字节码指令我就懂了,原来是通过Integer.valueOf 来做的一个int的自动装箱

11: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

所以,问题肯定出在Integer.valueOf里面,接着,我点开valueOf的源码

  1. public static Integer valueOf(int i) {
  2. if (i >= IntegerCache.low && i <= IntegerCache.high)
  3. return IntegerCache.cache[i + (-IntegerCache.low)];
  4. return new Integer(i);
  5. }

好家伙,这里用到了一个缓存类:IntegerCache

判断如果在缓存范围内,直接返回这个缓存类持有的引用,否则就new一个Integer对象

再点开这个缓存类,low=-128,high=127

这就解释了为什么100是true,500是false了

JDK为什么要设计这样一个很容易掉进去的坑呢?

其实,在valueOf方法上,官方已经给出了说明:

  1. /**
  2. * Returns an {@code Integer} instance representing the specified
  3. * {@code int} value. If a new {@code Integer} instance is not
  4. * required, this method should generally be used in preference to
  5. * the constructor {@link #Integer(int)}, as this method is likely
  6. * to yield significantly better space and time performance by
  7. * caching frequently requested values.
  8. *
  9. * This method will always cache values in the range -128 to 127,
  10. * inclusive, and may cache other values outside of this range.
  11. *
  12. * @param i an {@code int} value.
  13. * @return an {@code Integer} instance representing {@code i}.
  14. * @since 1.5
  15. */

大概意思就是,-128~127 的数据在 int 范围内是使用最频繁的,为了减少频繁创建对象带来的内存消耗,这里其实是用到了享元模式,以提高空间和时间性能。

既然Integer这样设计了,其他类会不会也有呢?

接着,我又看了其他数据类型,用缓存的还不少,这里我给各位列一下,防止你们以后踩坑

基本类型 包装类型 缓存范围
boolean Boolean -
byte Byte -128-127
short Short -128-127
int Integer -128-127
long Long -128-127
float Float -
double Double -

小伙伴们在开发过程中,也要注意,避免掉进这个坑里。

好了,今天的分享就到这里了,如果你觉得有用,麻烦给兄弟点个小赞,这样我才更有动力去分享更多技术干货~

原文链接:https://www.cnblogs.com/liumashaonian/p/17107167.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号