关于java:深入理解-Java-的整型类型如何实现-225

7次阅读

共计 1806 个字符,预计需要花费 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 的一个知识点。

可能有的敌人对于 doSomethingMagic 外面的代码有点摸不着头脑,让咱们先查看上图第 17 行 2 + 2 反编译进去的代码:

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

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

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

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

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

带着这个理念,咱们再看 doSomethingMagic 的代码就分明多了。

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

  • Class cache = Integer.class.getDeclaredClasses()[0]:通过 Integer.class.getDeclaredClasses() 办法获取 Integer 类的所有外部类,而后 [0] 取出第一个外部类,也就是 Integer$IntegerCache 类的 Class 对象,并将其赋值给变量 cache. Integer$IntegerCache 类是 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.

当初这个元素的值被第 133 个元素即 5 笼罩了,所以最初失去了 2 + 2 = 5。

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

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

正文完
 0