0

So basically I was doing some research because I was curious to see if it could be done and I found this code:

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];

      int  n = 2+2;
      System.out.println(n);
      System.out.printf("%d",2 + 2);
    }
}

I was simply curious why the printf statement would now return 5, but printing integer n would sill give me 4.

  • `println(n)` does not make use of the java.lang.Integer class at all. `printf` does, because every argument is boxed, since all arguments must be objects. – VGR Sep 04 '20 at 00:40

1 Answers1

3

Java caches 256 Integer objects representing the numbers from -128 to 127. When an int gets boxed to an Integer, if its value is between -128 and 127, the Integer object from the cache will be used. (Learn more here). How the language does this is implementation detail. In your version of Java, it stores this cache in an inner class in Integer, in an Integer[] field called cache. In some other version of Java, this might change, so your code might break.

What the first part of your code is doing, is getting the integer cache, and setting index 132 to be the same as index 133. Since this array starts from -128, index 132 would correspond to where 4 is, and index 133 would be where 5 is. This means you have replaced 4 in the cache with a 5.

The argument to printf, 2 + 2, first gets evaluated to 4. Then it gets boxed to an Integer. This is because printf only accepts an Object as its second parameter. Because 4 is between -128 and 127, the cache is used, and index 132 of the array is accessed, because that's where the Integer 4 would have been, if you haven't modified the array. But you have modified the array, so it got 5 instead.

On the other hand, println still prints 4 because println has an overload that accepts int, so no boxing occurs there.

By the way, you are not modifying "integer addition", you are just modifying "integer boxing".

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • 1
    re *you are just modifying "integer boxing"* -- or "corrupting memory", as we usually say it :-) – J.Backus Sep 04 '20 at 02:04
  • Thanks, this was a helpful explanation. I also wanted to know, would it be possible to make 2+2=5 in my println without boxing it to an Integer, or is that not possible? – Shrey Varma Sep 04 '20 at 18:19
  • 1
    As I said, you are never making `2 + 2 = 5`. You are just making `4 = 5`. If I `printf` 1+3, I will still get 5. Anyway, there's very little you can do with ints. Maybe self-modifying code? Seriously though, both of these approaches are extremely unsafe and unreliable. They could easily break in another Java version. @ShreyVarma – Sweeper Sep 05 '20 at 01:00
  • All right, I see what you mean. Yah, I never really wanted to use this code, I was just curious to see how it worked. – Shrey Varma Sep 05 '20 at 03:53