Почему Compiler / JVM не может сделать AutoBoxing «Просто работать»?

StackOverflow https://stackoverflow.com/questions/2602636

Вопрос

Автообоксинг довольно страшен. Пока я полностью понимаю разницу между == а также .equals Я не могу, но помочь, чтобы позволить следовать чему, черт возьми, ада из меня:

    final List<Integer> foo = Arrays.asList(1, 1000);
    final List<Integer> bar = Arrays.asList(1, 1000);
    System.out.println(foo.get(0) == bar.get(0));
    System.out.println(foo.get(1) == bar.get(1));

Это принты

true
false

Почему они сделали это таким образом? Это что-то делать с кэшированными целыми числами, но если это так, почему они не просто кэшируют все целые числа, используемые программой? Или почему JVM не всегда автоматически Unbox до примитива?

Печать false false или true true было лучше.

РЕДАКТИРОВАТЬ

Я не согласен о поломке старого кода. Имея foo.get(0) == bar.get(0) Верните true, вы уже сломали код.

Разве это не может быть решено на уровне компилятора, заменив целое число с Int в байтовом коде (до тех пор, пока он никогда не назначен NULL)

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

Решение

  • Почему они сделали это таким образом?

Каждое целое число между -128 и 127 кэшируется Java. Они сделали это, предположительно, для выгодной выгоды. Даже если они хотели вернуться на это решение сейчас, вряд ли они бы. Если кто-то построил код в зависимости от этого, их код сломался, когда он был выведен. Для кодирования хобби, это возможно, не имеет значения, но для корпоративного кода люди случаются расстраиваются, и случаются судебные иски.

  • Почему они не просто кэшируют все целые числа, используемые программой?

Все целые числа не могут быть кэшированы, потому что последствия памяти были бы огромными.

  • Почему JVM не всегда автоматически Unbox до примитивы?

Потому что JVM не может знать, что вы хотели. Кроме того, это изменение может легко сломать устаревший код, который не создан для обработки этого случая.

Если JVM для автоматического автоматического отключения примитивы на вызовы == эта проблема фактически станет более запутанным. Теперь вам нужно помнить, что == всегда сравнивает ссылки на объекты, если объекты не могут быть небоксыми. Это приведет к тому же странному запутанным случаям, как то, который вы указали выше.

Скорее, а затем слишком сильно беспокоиться об этом, просто помните это правило вместо этого:

НИКОГДА Сравните объекты с == Если вы не намерены сравнивать их по их ссылкам. Если вы это сделаете, я не могу придумать сценарий, в котором вы столкнетесь с проблемой.

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

Можете ли вы представить, насколько плохой производительность будет, если каждый Integer Перевел накладные расходы на интернет? Также не работает для new Integer.

Язык Java (не проблема JVM) не может всегда автоматически Unbox, потому что код, предназначенный для Pre-1.5 Java, должен все еще работать.

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

И из здесь

Результатом всей этой магии в том, что вы можете в значительной степени игнорировать различие между INT и целым числом, с несколькими предостережениями. Целочисленное выражение может иметь нулевое значение. Если ваша программа пытается autoonbox NULL, он бросит NullPointexception. Оператор == выполняет сравнение ссылочной идентификации по целочисленным выражениям и сравнениям равенства стоимости на выражениях Int. Наконец, есть расходы на производительность, связанные с боксом и распачкой, даже если это сделано автоматически

Если вы полностью пропустите AutoBoxing, вы все еще получаете это поведение.

final List<Integer> foo =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
final List<Integer> bar =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // true
System.out.println(foo.get(1) == bar.get(1)); // false

Будьте более явным, если вы хотите конкретное поведение:

final List<Integer> foo =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
final List<Integer> bar =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // false
System.out.println(foo.get(1) == bar.get(1)); // false

Это причина, почему Eclipse имеет Autoboxing в качестве предупреждения по умолчанию.

У многих людей есть проблемы с этим вопросом, даже люди, которые пишут книги о Java.

В Pro Java программирование, Несколько дюймов ниже были автор разговаривает о проблемах с использованием целых чисел Auto-Boxed в качестве ключа в идентификаторе HASHMAP, он использует целочисленные клавиши автоматического боксека в Solidhhashmap. Примерные значения, которые он использует, превышает 128, поэтому его вызов сборки мусора добится успеха. Если кто-то должен был использовать свой пример и использовать значения, меньшие, чем 128, его пример не удастся (из-за ключевого ключевого кэширования).

Когда вы пишете

foo.get(0)

Компилятор не имеет значения, как вы создали список. Он смотрит только на тип компиляции списка FOO. Итак, если это списокu003CInteger> , это будет относиться к этому как списокu003CInteger> , как это должно делать, и списокu003CInteger> Get () всегда возвращает целое число. Если вы хотите использовать ==, то вам нужно написать

System.out.println(foo.get(0).intValue() == bar.get(0).intValue());

нет

System.out.println(foo.get(0) == bar.get(0));

Потому что это имеет совершенно другое значение.

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