Как изменить целочисленное сложение в Java?

Sep 03 2020

По сути, я проводил некоторое исследование, потому что мне было любопытно посмотреть, можно ли это сделать, и я нашел этот код:

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);
    }
}

Мне было просто любопытно, почему оператор printf теперь возвращает 5, но печать целого числа n все равно дает мне 4.

Ответы

3 Sweeper Sep 04 2020 at 00:47

Java кэширует 256 Integerобъектов, представляющих числа от -128 до 127. Когда объект intпомещается в коробку Integer, если его значение находится между -128 и 127, Integerбудет использоваться объект из кеша. ( Узнайте больше здесь ). Как это делает язык - это детали реализации. В вашей версии Java этот кеш хранится во внутреннем классе Integerв Integer[]поле с именем cache. В какой-то другой версии Java это может измениться, поэтому ваш код может сломаться.

Первая часть вашего кода получает целочисленный кеш и устанавливает индекс 132 таким же, как индекс 133. Поскольку этот массив начинается с -128, индекс 132 будет соответствовать 4, а индекс 133 будет где 5. Это означает, что вы заменили 4 в кеше на 5.

Аргумент printf, 2 + 2сначала получает оценку до 4. Затем она получает коробку с Integer. Это потому, что он printfпринимает только Objectвторой параметр. Поскольку 4 находится в диапазоне от -128 до 127, используется кеш, и осуществляется доступ к индексу 132 массива, потому что там, где Integer4 был бы, если бы вы не изменили массив. Но вы изменили массив, поэтому вместо него он получил 5.

С другой стороны, по- printlnпрежнему выводится 4, потому что printlnимеется принимающая перегрузка int, поэтому там не происходит упаковки.

Кстати, вы не изменяете «целочисленное сложение», вы просто изменяете «целочисленный бокс».