Tuesday, September 16, 2014

2+2 = 5

Yup, it's actually possible to have 2+2=5. Or any other small number.

Interestingly, some JVM's have an Integer cache, where the numbers ranging from -128 to +127 are stored because they're assumed to be used more frequently and so that the Integer class can function with better memory efficiency (a rather interesting set of functions available in the Integer class. Have a look under the hood).

So if you write some code like this:
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");
        Integer[] array = (Integer[]) c.get(cache);
        array[132] = array[133];

        System.out.printf("%d", 2 + 2);
You can build from the commandline using
gedit Main.java;
javac Main.java;
java -cp /folder/containing/the/class/file/ Main

Where position 132 is where 4 is located and is being overwritten by the number in position 133, which is 5, the last printf will output 5. Rather cool, isn't it? :)
It's like tinkering with the foundations of the universe or DNA.

Why caching?
It puzzled me. What memory efficiency were they trying to achieve with caching?
Turns out that when you store a primitive datatype like int in an Integer class (called a boxing conversion), it's better for low-memory machines to have the integer use up only 8 bits, instead of the usual 16 bits. The cache helps in this storage of 8 bits, if we go with the assumption that numbers from -128 to +127 are the most frequently used integers. If integers beyond that range needs to be used, then the Integer class would automatically store them in a 16 bit memory location.

You can see this phenomenon in another piece of code (which works only if the specific JVM has implemented the cache):
Integer a = 1000, b = 1000;  
System.out.println(a == b); // outputs false  
Integer c = 100, d = 100;  
System.out.println(c == d); // outputs true

No comments: