Непоследовательное поведение на Java's ==
Вопрос
Рассмотрим этот код:
class test {
public static void main(String[] args) {
test inst_test = new test();
int i1 = 2000;
int i2 = 2000;
int i3 = 2;
int i4 = 2;
Integer Ithree = new Integer(2); // 1
Integer Ifour = new Integer(2); // 2
System.out.println( Ithree == Ifour );
inst_test.method( i3 , i4 );
inst_test.method( i1 , i2 );
}
public void method( Integer i , Integer eye ) {
System.out.println(i == eye );
}
}
Он печатает:
false
true
false
Я понимаю первое false
, оператор == проверяет, только если две ссылки работают над одним и тем же объектом, а в этом случае нет.
Следующее true
а также false
Попросите меня почесать голову. Почему Java рассматривает i3
а также i4
равен, но i1
а также i2
другой? Оба были завернуты в целое число, не должны оба оценить на ложь? Есть ли практическая причина этого несоответствия?
Решение
Автобоксинг примитивов в объекты (как используется в ваших вызовах для method
использует кэш из небольших значений. От Спецификация языка Java Раздел 5.1.7:
Если значение p в штучной упаковке верно, false, байт, символ в диапазоне u0000 до u007f, или int или короткое число между -128 и 127, тогда пусть R1 и R2 будут результатами любых двух преобразований бокса. р. Это всегда тот случай, когда r1 == r2.
Дискуссионная часть спецификации сразу после этого тоже интересна. Примечательно JVM может кэшировать более Значения, если это захочет - вы не можете быть уверены в результатах выполнения:
Integer i1 = 129;
Integer i2 = 129;
boolean b = (i1 == i2);
Другие советы
При автобоксинге, целые числа между -128 и 127 кэшируются, и возвращается тот же объект обертки. То же самое с логическими значениями и значениями ChAR между U0000 и U007F
Это то, что вы получаете большую часть времени, однако это зависит от реализации JVM.
Это связано с тем, что бокс делает целые числа ниже определенного значения (я думаю, 128) относятся к некоторому предварительному объекту и более высокие значения для новых объектов.
Автобоксинг использует Integer.valueof (i), не новое целое число (i), чтобы построить объект целого числа класса.
Как сказали другие, ValueOf () использует кэш, в основном для эффективности пространства.
Не используйте == На эталонных типах это почти всегда ошибка.
Целое число класса содержат кэш некоторых часто используемых экземпляров. Диапазон значений, как правило, варьируется от JVM к JVM (иногда также настраивается), но в целом соответствующий код - что -то вроде:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
(Код от Sun JDK 1.6)
Это похоже на запекание строк, поскольку он сохраняет память и позволяет тестовому равенству, используя ссылку (например, == на месте равно)
Я предполагаю, что обертка пытается минимизировать количество целочисленных объектов и создает только один объект, представляющий 2 слишком сохранение памяти.
Просто не забывайте никогда не использовать == на объектах, вы никогда не знаете, что происходит.
Автобоксинг используйте некоторый механизм кэширования. Обычно вам никогда не следует полагаться на ==
, всегда используйте equals
Чтобы проверить равенство.