March 15

Все ответы уже давно написаны

Источник изображения в заголовке Unsplash. Автор Steve Johnson .

Примерно с такой фразы началась техническая часть одного из моих собеседований. После очередной затяжки электронной сигареты собеседующий прислал ссылку.

В целом, крупный российский биржевой холдинг может себе позволить “лайвкодинг в блокноте”, о котором ведется множество дебатов в последнее время. А вот человек, покуривающий на фоне интернет-мема “Них** не понял, но очень интересно.”, и до этого момента вызывал сугубо желание завершить встречу досрочно. Но работая в компании, которая всем сердцем полюбила аутстаффинг, приходится в итоге действовать немного иначе.

Что же, отбросим лирику и перейдем к сути статьи. Как точно выглядел код для “расскажите, какой тут будет вывод” я уже не помню, но смысл был примерно следующий:

Integer a = new Integer(127);
Integer b = 127;
Integer c = 127;

Integer d = new Integer(128);
Integer e = 128;
Integer f = 128;

System.out.println(a == b);
System.out.println(a.equals(b));

System.out.println(b == c);
System.out.println(b.equals(c));

System.out.println(d == e);
System.out.println(d.equals(e));

System.out.println(e == f);
System.out.println(e.equals(f));

Про упаковку (boxing) и распаковку (unboxing) между примитивными типами и эквивалентными классами-обертками, я конечно знаю, как и про кеширование определенного диапазона значений. Но вот не припомню, даже за последние 5 лет разработки исключительно на Java, о каком-либо дефекте из-за попытки сравнения Integer через оператор. А вы встречали такие проблемы на практике?

После указания всей имеющейся вереницы true/false, я озвучил, что не на сто процентов уверен по части числа 128, но, вроде, кеширование заканчивается на 127. На что собеседующий, с посылом о необходимости знать такие догмы, написал в блокноте [-128; 127].

Если заглянуть в спецификацию языка, то там можно найти отдельный раздел 5.1.7 “Boxing Conversion”, где будет упомянут такой диапазон кеширования для всех целочисленных типов. Но и обязательные требования, что выходить за рамки данного диапазона недопустимо, отсутствуют. Наоборот там прямо указывается:

Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

И вот именно в части Integer окончание диапазона кеширования на 127 уже давно не является догмой. Даже если говорить исключительно про OpenJDK и HotSpot JVM, которые принято считать основными реализациями.

Изменить результат сравнения e и f для значения 128 можно путем задания одной опции JVM:

-Djava.lang.Integer.IntegerCache.high=128

При этом нижняя граница -128 остается зафиксированной, и не предусмотренно установки верхней границы кеширования менее 127. Также существует второй вариант указания опции через -XX:AutoBoxCacheMax, которая будет иметь приоритет над первой.

Автоматические упаковка и распаковка появились еще в 5 версии Java. А вот возможность изменения верхней границы кеширования Integer в 1.6.0_14, если верить журналам изменений.

Так что, в попытке исключить “рассказывание уже давно написанных ответов”, главное не забывать перепроверить актуальность уникальных задач из 2004 года.

P.S. Начиная с 9 версии конструкторы класса Integer помечены @Deprecated.