深入理解 Java 的整型类型:如何实现 2+2=5?

简介: 深入理解 Java 的整型类型:如何实现 2+2=5?

在开始关于 Java 的整型类型讨论之前,让我们先看下这段神奇的Java代码:


public static void main(String[] args) throws Exception {
      doSomethingMagic();
      System.out.printf("2 + 2 = %d", 2 + 2);
}



执行结果,控制台打印的内容:2 + 2 = 5


那么 doSomethingMagic 方法到底做了什么神奇的事情呢?


private static void doSomethingMagic() throws Exception {
   Class cache = Integer.class.getDeclaredClasses()[0];
   Field c = cache.getDeclaredField("cache");
   c.setAccessible(true);
   Integer[] array = (Integer[]) c.get(cache);
   array[132] = array[133];
}



所以这个例子其实包含了 Java 中整型类型 Integer 的一个知识点。


image.png


可能有的朋友对于 doSomethingMagic 里面的代码有点摸不着头脑,让我们先查看上图第17行 2 + 2 反编译出来的代码:


image.png


编译器将 2 + 2 的值先计算出来,等于 4.


最后 System.out.println 打印出来的值,实际上是 Integer.valueOf(4) 表达式的返回值。


那么我们进一步查看 JDK 里 Integer.valueOf 的实现:


image.png


上面的实现代码,从 830 行到 832行,逻辑是:如果 valueOf 方法调用的参数 i 在 IntegerCache.low 和 IntegerCache.high 之间,即位于 [-128, 127] 的闭区间,则直接从 IntegerCache 这个内部类的缓存数组里取出元素,作为方法的返回值。


只有当输入参数 i 不在 [-128,127] 区间内,才执行代码第 832 行,基于输入参数 i 创建一个新的 Integer 实例。


带着这个理念,我们再看 doSomethingMagic 的代码就清楚多了。


image.png


这段代码的作用是访问 Java Integer 类实现的某个内部类维护的缓存数组,对其中一个元素的值进行修改。具体解释如下:


  • Class cache = Integer.class.getDeclaredClasses()[0]:通过 Integer.class.getDeclaredClasses() 方法获取 Integer 类的所有内部类,然后 [0] 取出第一个内部类,也就是 IntegerI n t e g e r C a c h e 类的 C l a s s 对象,并将其赋值给变量 c a c h e . I n t e g e r IntegerCache 类的 Class 对象,并将其赋值给变量 cache. IntegerIntegerCache类的Class对象,并将其赋值给变量cache.IntegerIntegerCache 类是 Java 8 引入的一个内部类,它用于缓存整数对象(Integer 类型的对象),默认缓存范围是 -128 到 127。

  • Field c = cache.getDeclaredField(“cache”): 接下来,通过 cache.getDeclaredField(“cache”) 方法获取 cache 字段的 Field 对象,并将其赋值给变量 c。该字段存储了 Integer 类的缓存数组。

  • c.setAccessible(true):通过 c.setAccessible(true) 方法设置 c 字段的访问权限,以便可以通过反射来修改该字段的值。

  • Integer[] array = (Integer[]) c.get(cache):通过 c.get(cache) 方法获取缓存数组的值,并将其强制转换为 Integer 类型的数组,然后将其赋值给变量 array.

  • array[132] = array[133]:最后,将缓存数组中下标为 133 的元素的值赋给下标为 132 的元素,从而修改了缓存数组中下标为 132 的元素的值。


我们从 Eclipse 调试器里发现,Integer 内部类的 cache 数组里,第 132 个元素的值为 4,第 133 个元素的值为 5. 本来 Integer.valueOf 方法,对于输入 4,从Integer 内部类缓存数组里,返回第 132 个元素的值,即 4.


image.png


现在这个元素的值被第 133 个元素即 5 覆盖了,所以最后得到了 2 + 2 = 5。


用一句话概括这个场景:2 + 2 = 4 = Integer.valueOf(4) = 5 ( 因为 4 在 Integer 内部类 cache 数组里对应的记录,已经被我们的 doSomethingMagic 方法,显式从 4 替换成了 5)。


这就是 Java 里实现 2 + 2 = 5 这个算式的方法之一。



相关文章
|
9天前
|
Java
java基础(10)数据类型中的整数类型
Java中的整数类型包括byte、short、int和long。整数字面值默认为int类型,加L表示long类型。整数字面值可以是十进制、八进制(0开头)或十六进制(0x开头)。小容量类型(如int)可自动转换为大容量类型(如long),但大容量转小容量需强制转换,可能导致精度损失。
22 2
|
5月前
|
存储 安全 Java
Java整型数据详解
Java整型数据详解
45 0
|
5月前
|
存储 Java 定位技术
轻松理解Java中的数据类型和变量
轻松理解Java中的数据类型和变量
21 0
|
10月前
|
存储 Oracle Java
一文带你了解Java最基本的数据类型和变量
一文带你了解Java最基本的数据类型和变量
65 0
|
12月前
|
存储 缓存 Java
深入理解 Java 的整型类型:如何实现 2+2=5?
深入理解 Java 的整型类型:如何实现 2+2=5?
|
存储 Oracle Java
java-数据类型与变量(下)
java-数据类型与变量(下)
70 0
|
存储 Oracle Java
Java变量与数据类型
Java变量与数据类型
157 0
|
存储 编解码 Oracle
【Java基础篇】数据类型与变量
【Java基础篇】数据类型与变量
101 0
|
存储 Oracle Java
【Java入门】数据类型与变量(二)
【Java入门】数据类型与变量(二)
【Java入门】数据类型与变量(一)
【Java入门】数据类型与变量(一)
下一篇
无影云桌面