奇怪的Java题:为什么128 == 128返回为False,而127 == 127会返回为True?

简介:

这是我们今天要讨论的话题,因为我觉得它非常的有趣。

如果你运行如下代码:


  
  
  1. class  A 
  2.     public static void main(String[] args)  
  3.     { 
  4.         Integer a = 128, b = 128; 
  5.         System.out.println(a == b); 
  6.         Integer c = 127, d = 127; 
  7.         System.out.println(c == d); 
  8.     } 
  9.  

你会得到如下结果:


  
  
  1. false 
  2. true  

运行代码

我们知道,如果两个引用指向同一个对象,那么==就成立;反之,如果两个引用指向的不是同一个对象,那么==就不成立,即便两个引用的内容是一样的。因此,结果就会出现false。

这是非常有趣的地方。如果你查看Integer.Java类,你会找到IntegerCache.java这个内部私有类,它为-128到127之间的所有整数对象提供缓存。

这个东西为那些数值比较小的整数提供内部缓存,当进行如此声明时:


  
  
  1. Integer c = 127 

它的内部就是这样的:


  
  
  1. Integer var3 = Integer.valueOf(127); 

其实我通过将A.class文件反编译后,代码如下图:

将A.class文件反编译

如果我们观察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.     }  

如果值在-128到127之间,它就会返回该缓存的实例。

因此。。。


  
  
  1. Integer c = 127, d = 127; 

两者指向同样的对象。

这就是为什么下面这段代码的结果为true了:


  
  
  1. System.out.println(c == d); 

现在你可能会问,为什么会为-128到127之间的所有整数设置缓存?

这是因为在这个范围内的小数值整数在日常生活中的使用频率要比其它的大得多,多次使用相同的底层对象这一特性可以通过该设置进行有效的内存优化。你可以使用reflection API任意使用这个功能。

运行下面的这段代码,你就会明白它的神奇所在了。


  
  
  1. public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { 
  2.  
  3.       Class cache = Integer.class.getDeclaredClasses()[0];  
  4.       Field myCache = cache.getDeclaredField("cache"); 
  5.       myCache.setAccessible(true); 
  6.  
  7.       Integer[] newCache = (Integer[]) myCache.get(cache);  
  8.       newCache[132] = newCache[133];  
  9.  
  10.       int a = 2; 
  11.       int b = a + a; 
  12.       System.out.printf("%d + %d = %d", a, a, b); // 
  13.     }  

打印结果竟然是:


  
  
  1. 2 + 2 = 5  

打印结果

我们再次看一下反汇编代码:

反汇编代码

是不是又和上面的是同一个问题呢?

但是结果为什么是 2 + 2 = 5 呢?

我们继续去看一下 Integer 源码,去深入了解 Integer 缓存机制,下面截个图:

Integer 源码,去深入了解 Integer 缓存机制

根据源码可以发现最后修改 Integer 缓存上限时候的方法有点小瑕疵。我们看看Api给我们怎么建议的一段话:


  
  
  1. the size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option

原来我们只需要:运行时设置 -XX:AutoBoxCacheMax=133 就OK。




本文作者:佚名
来源:51CTO
目录
相关文章
|
6月前
|
缓存 Java API
为什么Java中“1000==1000”为false,而”100==100“为true
为什么Java中“1000==1000”为false,而”100==100“为true
44 0
|
6月前
|
Java
java判断时间是否为节假日(或指定的日期),是的话返回true,否返回false
java判断时间是否为节假日(或指定的日期),是的话返回true,否返回false
116 0
|
6月前
|
Java
java判断时间是否为节假日(或指定的日期),是的话返回true,否返回false
java判断时间是否为节假日(或指定的日期),是的话返回true,否返回false
191 0
|
6月前
|
Java
Java【问题 05】yml配置文件boolean一直为false问题分析解决
Java【问题 05】yml配置文件boolean一直为false问题分析解决
184 0
Java用户线程和守护线程,线程默认Daemon值是false吗?
Java用户线程和守护线程,线程默认Daemon值是false吗?
Java用户线程和守护线程,线程默认Daemon值是false吗?
|
存储 JSON 缓存
Java小技能:多级菜单排序并返回树结构菜单列表
需求: 菜单管理(服务商角色配置权限管理)、文章分类、MCC类目、区域信息。
403 0
Java小技能:多级菜单排序并返回树结构菜单列表
|
SQL JSON Java
JAVA返回树结构(宇宙第一详细教程)
JAVA返回树结构(宇宙第一详细教程)
JAVA返回树结构(宇宙第一详细教程)
|
Java 测试技术
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。(Java语言实现)
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。(Java语言实现)
169 0
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。(Java语言实现)
下一篇
无影云桌面