问题描述
与我同在,我知道这是一个奇怪的问题。
我刚刚偶然发现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)
当我尝试使用class
和getClass
时,它们都不是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
只是JavaInteger
的包装,不是吗?
不是。通常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)