【问题标题】:Using reflection to override 2 + 2 = 5使用反射覆盖 2 + 2 = 5
【发布时间】:2020-09-04 21:32:42
【问题描述】:

请耐心等待,我知道这是一个奇怪的问题。

我刚刚偶然发现了 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)

当我尝试使用 Integer 时,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 的愚蠢目标?

【问题讨论】:

  • 相关(可能重复):stackoverflow.com/questions/63733340/…
  • @VGR 好链接。可能不是重复的,因为问题是如何在 Scala 中重现。
  • @VGR 正如 Dmytro 所说,它没有回答我的问题,因为我对这段 Java 代码的 Scala 翻译特别感兴趣,但是无论如何解释引擎盖下发生的事情都非常有帮助。感谢您提供信息丰富的链接!

标签: java scala reflection scala-java-interop


【解决方案1】:

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

Int.getClassgetClass在类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对应Javaint

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

【讨论】:

    【解决方案2】:

    如果您检查 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 类的“缓存”字段,即从 -128 到 127 的值。但在它们保持在一起的数组中,所以值 0 索引实际上是 128(因为首先有 -128 个值) + 0。

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

    你的数组[132] = 数组[133];表达式使缓存中的 4 = 5。所以每当应用程序从缓存中调用索引 4 时,都会返回整数 5。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-19
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      • 2018-03-03
      相关资源
      最近更新 更多