Вопрос

Я только что видел код, похожий на этот:

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

При запуске этот блок кода будет распечатан:

false
true

Я понимаю, почему первое таково false:поскольку эти два объекта являются отдельными объектами, то == сравнивает ссылки.Но я не могу понять, почему возвращается второе утверждение true?Существует ли какое-то странное правило автоматической блокировки, которое срабатывает, когда значение целого числа находится в определенном диапазоне?Что здесь происходит?

Это было полезно?

Решение

То true линия фактически гарантируется языковой спецификацией. От Раздел 5.1.7.:

Если в боксе значения P FAXT, FALSE, BYTE, CHAN в диапазоне U0000 до u007f, или int или короткое число между -128 и 127, то пусть R1 и R2 являются результатами любых двух преобразований бокса из с. Это всегда тот случай, когда R1 == R2.

Обсуждение продолжается, что предполагает, что хотя ваша вторая линия выпуска гарантирована, первая не (см. В последнем абзаце, указанном ниже):

В идеале бокс данная примитивная ценность P, всегда будет давать одинаковую ссылку. На практике это может не осуществимо использовать существующие методы реализации. Правила выше являются прагматичным компромиссом. Вышеуказанное предложение о последнем пункте требует, чтобы определенные общие ценности всегда были введены в неразличимые объекты. Реализация может кэлить их, лениво или с нетерпением.

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

Это гарантирует, что в большинстве случаев поведение будет желательным, не навязывая неоправданную штраф производительности, особенно на небольших устройствах. Меньше ограниченных на память реализации могут, например, кэшировать все символы и шорты, а также целые числа и длительные в диапазоне -32K - + 32K.

Другие советы

public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

Выход:

false
true

Yep первый выход производится для сравнения ссылки; «А» и «B» - это две разные ссылки. В пункте 1 на самом деле созданы две ссылки на то, что похоже как -

Integer a = new Integer(1000);
Integer b = new Integer(1000);

Второй выход производится, потому что JVM пытается сохранить память, когда Integer падает в диапазоне (от -128 до 127). В пункте 2 новая ссылка на тип типа не создается для 'D'. Вместо того, чтобы создать новый объект для ссылочной переменной типа целочисленного типа «D», она назначена только ранее созданным объектом, на который ссылается «C». Все это сделано JVM.

Эти правила сохранения памяти не только для целого числа. Для цели экономии памяти два экземпляра следующих объектов обертки (при создании через бокс) всегда будут == где их примитивные значения одинаковы -

  • Логический
  • Байт
  • Характер от u0000. к \u007f (7f 127 в десятичном периоде)
  • Коротко и целое число от -128 к 127

Целочисленные объекты в некоторых диапазоне (я думаю, может быть, -128-127) получить кэшированную и повторно использовать. Целые числа вне этого диапазона получают новый объект каждый раз.

Да, существует странное правило автообоксинга, в которое ударяет, когда значения находятся в определенном диапазоне. Когда вы назначаете постоянную переменную объекта, ничего в определении языка не говорит о новом объекте должен быть созданным. Это может повторно использовать существующий объект из кэша.

На самом деле, JVM обычно хранит кэш небольших целых чисел для этой цели, а также такие значения, как Boolean.true и Boolean.False.

Это интересный момент. В книге Эффективная Java Предлагает всегда переопределить равных ваших собственных классах. Кроме того, чтобы проверить равенство для двух экземпляров объектов класса Java всегда используйте метод равенства.

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a.equals(b));

        Integer c = 100, d = 100;
        System.out.println(c.equals(d));
    }
}

Возвращает:

true
true

Я предполагаю, что Java держит кэш маленьких целых чисел, которые уже «в штучной упаковке», потому что они настолько очень распространены, и он экономит много времени, чтобы повторно использовать существующий объект, чем создать новый.

В Java бокс работает в диапазоне от -128 и 127 для целого числа. Когда вы используете цифры в этом диапазоне, вы можете сравнить его с оператором ==. Для целочисленных объектов вне диапазона вы должны использовать равных.

Прямое задание int Lobalal к целочисленной ссылке является примером автоматического бокса, где буквальное значение для кода преобразования объекта обрабатывается компилятором.

Так во время компилятора Compilation Compiler преобразует Integer a = 1000, b = 1000; к Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.

Так что, это Integer.valueOf() метод, который фактически дает нам целочисленные объекты, и если мы посмотрим на исходный код Integer.valueOf() Метод мы можем четко видеть метод кэшировать целочисленные объекты в диапазоне от -128 до 127 (включительно).

/**
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
 public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high)
         return IntegerCache.cache[i + (-IntegerCache.low)];
     return new Integer(i);
 }

Поэтому вместо создания и возвращения новых целочисленных объектов, Integer.valueOf() Метод возвращает целочисленные объекты из внутреннего IntegerCache Если прошедший int listeral превышает -128 и менее 127.

Java кэширует эти целочисленные объекты, потому что этот диапазон целых чисел использует много в повседневной программировании, который косвенно спасает некоторую память.

Кэш инициализируется на первом использовании, когда класс загружается в память из-за статического блока. Максимальный диапазон кеша может управляться -XX:AutoBoxCacheMax Опция JVM.

Это поведение кэширования не применяется только к целочисленным объектам только, аналогично целочисленным. INTeGerCache у нас также ByteCache, ShortCache, LongCache, CharacterCache для Byte, Short, Long, Character соответственно.

Вы можете прочитать больше на моей статье Java Integer Cache - почему integer.valueof (127) == integer.valueof (127) верно.

В Java 5 была введена новая функция для экономии памяти и повышения производительности при обработке объектов целочисленного типа.Целочисленные объекты кэшируются внутри компании и повторно используются через те же объекты, на которые даны ссылки.

  1. Это применимо для целых значений в диапазоне от -127 до +127 (Максимальное целое значение).

  2. Это целочисленное кэширование работает только при автоматической загрузке.Целочисленные объекты не будут кэшироваться при их создании с использованием конструктора.

Для получения более подробной информации, пожалуйста, перейдите по ссылке ниже:

Подробный целочисленный кэш

Если мы проверяем исходный код Integer Obeject, мы найдем источник valueOf Метод так же, как это:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

что может объяснить, почему Integer объекты, которые в диапазоне от -128 (Integer.low) до 127 (Integer.high), одни и те же ссылки на объекты во время автообкинга. И мы можем видеть, что есть класс IntegerCache заботится о Integer массив кеша, который является частным статическим внутренним классом Integer сорт.

Есть еще один интересный пример может помочь нам понять эту странную ситуацию:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

      Class cache = Integer.class.getDeclaredClasses()[0]; 
      Field myCache = cache.getDeclaredField("cache"); 
      myCache.setAccessible(true);

      Integer[] newCache = (Integer[]) myCache.get(cache); 
      newCache[132] = newCache[133]; 

      Integer a = 2;
      Integer b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //The output is: 2 + 2 = 5    

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top