Как изменить целочисленное сложение в Java?
По сути, я проводил некоторое исследование, потому что мне было любопытно посмотреть, можно ли это сделать, и я нашел этот код:
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.
Ответы
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, поэтому там не происходит упаковки.
Кстати, вы не изменяете «целочисленное сложение», вы просто изменяете «целочисленный бокс».