суббота, 9 октября 2010 г.

Трюки с оберточными типами

Недавно коллеги заставили меня немножечко удивиться офигеть. Началось с того, что прислали вот такой код, и спросили каким же будет результат:
Integer a1 = 123;
Integer a2 = 123;
boolean result = a1 == a2;

Наивно полагая, что я неплохо знаю основы языка, я конечно же ответил false.
Оказалось что во первых: "а вот и нифига не правильно (т.е. result == true)", a во вторых: "такой ответ не всегда такой".

Итак:
Integer это самый обычный класс, и из 'общей картины' выделяется только тем, что для него работает автобоксинг.
И по этому в выражении a1==a2 сравниваются не сами числа (в нашем случае 123), а объектные ссылки.
И по этому объектные ссылки в нашем примере должны быть разные.
НО! result==true!?

Как оказалось есть еще 2 момента:
Автобоксинг эквивалентен вызовом Integer.valueOf(int).
Объекты (instances) для чисел от -128 до 127 кешируются.

Поэтому в случае:
Integer a1 = 123;
Integer a2 = 123;
boolean result = a1 == a2;
мы имеем 2 ссылки на один и тот же объект и result==true.
А вот в случае:
Integer a1 = 1234;
Integer a2 = 1234;
boolean result = a1 == a2;
получаем 2 разных объекта и result==false.

Выводы:
1. Детали можно узнаь просмотрев реализацию java.lang.Integer.valueOf(int).
2. Подобное кеширование реализовано для всех целочисленных оберточных типов.
3. Подобный механизм кеширования используется для java.math.BigBecimal. Кешируются нули (т.е. варианты значений 0).
4. +1 к моему списку трюков мира Java.

И в завершение:
public class IntegerCachingTest {

 public static final int LESS_TAHAN_127 = 100;

 public static final int MORE_TAHAN_127 = 1000;

 @Test
 public void testAutoboxing_LessThan127() {
  Integer a1 = LESS_TAHAN_127;
  Integer a2 = LESS_TAHAN_127;

  assertSame(a1, a2);
 }

 @Test
 public void testAutoboxing_MoreThan127() {
  Integer a1 = MORE_TAHAN_127;
  Integer a2 = MORE_TAHAN_127;

  assertNotSame(a1, a2);
 }

 @Test
 public void testInstantiation_LessThan127() {
  Integer a1 = new Integer(LESS_TAHAN_127);
  Integer a2 = new Integer(LESS_TAHAN_127);

  assertNotSame(a1, a2);
 }

 @Test
 public void testInstantiation_MoreThan127() {
  Integer a1 = new Integer(MORE_TAHAN_127);
  Integer a2 = new Integer(MORE_TAHAN_127);

  assertNotSame(a1, a2);
 }

 @Test
 public void testValueOf_LessThan127() {
  Integer a1 = Integer.valueOf(LESS_TAHAN_127);
  Integer a2 = Integer.valueOf(LESS_TAHAN_127);

  assertSame(a1, a2);
 }

 @Test
 public void testValueOf_MoreThan127() {
  Integer a1 = Integer.valueOf(MORE_TAHAN_127);
  Integer a2 = Integer.valueOf(MORE_TAHAN_127);

  assertNotSame(a1, a2);
 }
}

Комментариев нет:

Отправить комментарий