Непоследовательное поведение на Java == - PullRequest
8 голосов
/ 19 июля 2009

Рассмотрим этот код:

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 разными? Оба были обернуты в Integer, разве оба не должны оцениваться как ложные? Есть ли практическая причина такого несоответствия?

Ответы [ 7 ]

15 голосов
/ 19 июля 2009

Автобокс примитивов в объекты (как в ваших вызовах method использует кэш небольших значений. Из раздела Java Language Specification 5.1.7 :

Если значение p в боксе равно true, false, байт, символ в диапазоне \ u0000 до \ u007f, или int или short число от -128 до 127, то пусть r1 и r2 будут результатами любых двух конверсии бокса р. Это всегда случай, когда r1 == r2.

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

Integer i1 = 129;
Integer i2 = 129;
boolean b = (i1 == i2);
7 голосов
/ 19 июля 2009

При автобоксировании целые числа от -128 до 127 кэшируются, и возвращается тот же объект-оболочка. То же самое с логическими значениями и значениями символов между \ u0000 и \ u007F

Это то, что вы получаете большую часть времени, однако это зависит от реализации JVM.

2 голосов
/ 19 июля 2009

Это связано с тем, что в боксах целые числа ниже определенного значения (я думаю, 128) относятся к какому-либо заранее созданному объекту, а более высокие значения - к новым объектам.

1 голос
/ 19 июля 2009

Автобокс использует Integer.valueOf (i) , а не new Integer (i), для создания объекта класса Integer.

Как уже говорили другие, valueOf () использует кеш, в основном для экономии пространства.

Не используйте == для ссылочных типов, это почти всегда ошибка.

0 голосов
/ 28 января 2010

Автобокс использует некоторый механизм кэширования. Обычно вам никогда не следует полагаться на ==, всегда используйте equals для проверки равенства.

0 голосов
/ 19 июля 2009

Целочисленный класс содержит кэш некоторых часто используемых экземпляров. Диапазон значений обычно варьируется от 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)

это похоже на интернирование строк, поскольку оно экономит память и позволяет проверять равенство, используя ссылку (например, == вместо равно )

0 голосов
/ 19 июля 2009

Я бы предположил, что обертка пытается минимизировать количество целочисленных объектов и создает только один объект, представляющий 2, также экономят память.

Только не забывайте никогда не использовать == на объектах, которые вы никогда не знаете, что происходит.

...