Почему компилятор/JVM не может только сделать автоупаковку “просто работать”?

Автоупаковка довольно страшна. В то время как я полностью понимаю различие между == и .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, всегда автоматической, распаковывают к примитиву?

Печать ложной лжи или верный верный была бы путем лучше.

Править

Я не соглашаюсь о поломке старого кода. При наличии foo.get(0) == bar.get(0) возвратите true, Вы уже взломали код.

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

12
задан Pyrolistical 8 April 2010 в 20:11
поделиться

5 ответов

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

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

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

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

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

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

Если JVM автоматически распаковывает примитивы при вызове ==, эта проблема станет БОЛЬШЕ запутанной. Теперь вам нужно помнить, что == всегда сравнивает ссылки на объекты, если только объекты не могут быть распакованы. Это вызовет еще более странные запутанные случаи, подобные тому, который вы указали выше.

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

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

11
ответ дан 2 December 2019 в 04:42
поделиться

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

И из здесь

Результатом всей этой магии является то, что вы можете в значительной степени игнорировать различие между int и Integer, с некоторыми оговорками. Целочисленное выражение может иметь нулевое значение. Если ваша программа попытается автоответить null, она выдаст исключение NullPointerException. Оператор == выполняет сравнения эталонных идентификаторов в целочисленных выражениях и сравнения на равенство значений в выражениях типа int. Наконец, существуют затраты на производительность, связанные с упаковкой и распаковкой, даже если это делается автоматически

5
ответ дан 2 December 2019 в 04:42
поделиться

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

В Pro Java Programming всего в нескольких дюймах ниже автор говорит о проблемах с использованием автоматически упакованных целых чисел в качестве ключа в IdentityHashMap, он использует автоматические вставки целочисленных ключей в WeakHashMap. Используемые им примерные значения больше 128, поэтому его вызов сборки мусора завершается успешно. Если бы кто-то использовал его пример и использовал значения меньше 128, его пример потерпел бы неудачу (из-за постоянного кэширования ключа).

3
ответ дан 2 December 2019 в 04:42
поделиться

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

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

7
ответ дан 2 December 2019 в 04:42
поделиться

Если вы полностью пропустите автобоксинг, вы все равно получите такое поведение.

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 имеет автобоксинг как предупреждение по умолчанию.

4
ответ дан 2 December 2019 в 04:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: