使用反射覆盖2 + 2 = 5

问题描述

与我同在,我知道这是一个奇怪的问题。

我刚刚偶然发现Java的反射库,特别是a video by Lex Fridman中的这段代码覆盖了2 + 2 = 5

import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) 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];

        System.out.printf("%d",2 + 2);
    }
}

我正在尝试通过将其转换为等效的Scala形式来环绕其工作,但是由于Int.getClass.getDeclaredClasses返回了一个空数组,因此它并未编译:

import java.lang.reflect.Field

val cache: Class[_] = Int.getClass.getDeclaredClasses.head
// above line throws java.util.NoSuchElementException: next on empty iterator

val c: Field = cache.getDeclaredField("cache")
c.setAccessible(true)
val array = c.get(cache).asInstanceOf[Array[Int]]
array(132) = 5

println(2+2)

当我尝试使用classgetClass时,它们都不是Integer下的方法,因此我尝试使用Int来代替。我给人的印象是Scala的Int只是Java的Integer的包装,不是吗?

我也尝试过:

  • new Integer()(相对于“重载方法构造函数Integer with Alternatives”)
  • new Int()(“ Int类是抽象的;无法实例化”)
  • class T extends Int ... new T.getClass....扩展Int和Integer(来自最终类的非法继承)

为什么这在Java无法与Scala一起编译的地方起作用?如何在Scala中实现愚蠢的2 + 2 = 5目标?

解决方法

java.lang.Integer应该代替scala.Int

在类Int.getClass的伴随对象上调用

getClass Int,这是错误的。

将代码翻译成Scala是

val cache = classOf[Integer].getDeclaredClasses.apply(0)
val c = cache.getDeclaredField("cache")
c.setAccessible(true)
val array = c.get(cache).asInstanceOf[Array[Integer]]
array(132) = array(133)
println(2 + 2) // 5

我给人的印象是Scala的Int只是Java Integer的包装,不是吗?

不是。通常scala.Int对应于Java int

https://github.com/scala/scala/blob/2.13.x/src/library/scala/Int.scala

,

如果您在IntegerCache类中检查Integer内部类。实现的某些部分如下:

        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

默认情况下,整数在-128(低)和127(高)之间(可能因为在典型应用中使用最多的整数而​​可能选择)。缓存大小为256(因此-和+值将保持在一起)

在您的应用程序中,您将获得Integer类的“ cache”字段,该字段的值是-128至127。但是在数组中它们保持在一起,因此值0索引实际上是128(因为首先有-128值) + 0。

0 -> 128
1 -> 129
2 -> 130
3 -> 131
4 -> 132
5 -> 133

您的array [132] = array [133];表达式在缓存中使4 = 5。因此,每当应用程序从缓存中调用索引4时,都将返回整数5。

对于Scala部分,我没有使用Scala的经验,但是它不使用JVM只是为了将自身编译为字节码吗?因此,也许Scala不使用JDK,并且Int实现有所不同,这就是导致错误的原因(似乎可以根据@Dmytro Mitin的回答从JDK使用Integer)