2

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?

James Whiteley
  • 3,363
  • 1
  • 19
  • 46
  • 2
    Related (and possible duplicate): https://stackoverflow.com/questions/63733340/how-to-modify-integer-addition-in-java – VGR Sep 05 '20 at 01:35
  • @VGR Good link. Probably not a duplicate because the question was how to reproduce in Scala. – Dmytro Mitin Sep 05 '20 at 07:37
  • @VGR as Dmytro says, it doesn't answer my question as I'm specifically interested in the Scala translation of this Java code, but the explanation of what's happening under the hood is very helpful regardless. Thank you for the informative link! – James Whiteley Sep 05 '20 at 19:31

2 Answers2

5

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

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
1

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)

cmlonder
  • 2,370
  • 23
  • 35