英文:
Using reflection to override 2 + 2 = 5
问题
请容我稍等,我知道这是一个奇怪的问题。
我刚刚偶然发现了Java的反射库,特别是来自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
// 上面这行会抛出 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具有多个重载方法的选择”)new Int()
(“类Int是抽象的,无法实例化”)- 将Int和Integer都扩展为
class T extends Int ... new T.getClass....
(从最终类进行非法继承)
为什么在Java中可以工作,但在Scala中无法编译?如何在Scala中实现我愚蠢的目标 2 + 2 = 5
?
英文:
Bear with me, I understand this is a weird problem to have.
I have just stumbled across Java's reflection library, specifically this bit of code from a video by Lex Fridman which overrides 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);
}
}
I am trying to wrap my head around what it's doing by translating it into its equivalent Scala form, but it isn't compiling as Int.getClass.getDeclaredClasses
returns an empty array:
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)
Neitherclass
nor getClass
were methods under Integer
when I tried using that, so I tried with Int
instead; I was under the impression that Scala's Int
is just a wrapper around Java's Integer
- is this not the case?
I have also tried:
new Integer()
(complained about "overloaded method constructor Integer with alternatives")new Int()
("class Int is abstract; cannot be instantiated")- Extending both Int and Integer with
class T extends Int ... new T.getClass....
(illegal inheritance from final class)
Why does this work in Java where it doesn't compile with Scala? How can I achieve my stupid goal of 2 + 2 = 5
in Scala?
答案1
得分: 5
java.lang.Integer
应该替代 scala.Int
。
Int.getClass
是在类 Int
的伴生对象上调用的 getClass
,这是错误的。
代码翻译成 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
英文:
java.lang.Integer
should be instead of scala.Int
.
Int.getClass
is getClass
invoked on the companion object of class Int
, which is wrong.
Translation of the code into Scala is
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
> I was under the impression that Scala's Int
is just a wrapper around Java's Integer
- is this not the case?
It's not. Normally scala.Int
corresponds to Java int
.
https://github.com/scala/scala/blob/2.13.x/src/library/scala/Int.scala
答案2
得分: 1
如果您查看Integer
类中的IntegerCache
内部类。部分实现如下:
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
默认情况下,IntegerCache
会缓存介于-128(low)和127(high)之间的整数(可能是因为在典型应用程序中这些整数使用最频繁)。缓存大小为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
)。
英文:
If you check IntegerCache
inner class inside Integer
class. Some part of the implementation as follows:
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
By default Integers between -128 (low) and 127 (high) (probably choiced because these are the most used ones in a typical application). And cache size is 256 (so that - and + values will be keep together)
In your application, you get "cache" field of Integer class which is the values from -128 to 127. But in the array they keep together, so value 0 index is actually 128 (because there are -128 values first) + 0.
0 -> 128
1 -> 129
2 -> 130
3 -> 131
4 -> 132
5 -> 133
And your array[132] = array[133]; expression makes 4 = 5 in the cache. So whenever an application calls the index of 4 from the cache, Integer 5 will be returned.
For the Scala part, I don't have experience in Scala but does not it use the JVM just to compile itself to byte code? So maybe Scala does not use the JDK and its Int implementation is different which is the reason you get the error (seems like it is possible to use Integer from JDK based on @Dmytro Mitin's answer)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论