Обычно компилятор генерирует код для выполнения упаковки и распаковывания. Но что делает компилятор, если помещенные в коробку значения не нужны? (Стандарт Oracle) компилятор, достаточно умный для оптимизации его далеко?
Смотрите на этот метод:
public static void requireInRange(int index, Object[] array) {
if(index < 0 || index >= array.length)
throw new IndexOutOfBoundsException();
}
Единственная релевантная информация array.length
, таким образом, было бы бесполезно упаковать каждое значение массива, например. Как в этом коде:
int[] anArray = {3, 4, 2};
requireInRange(3, anArray);
Компилятор на самом деле введет код для упаковки каждого значения массива?
В вашем коде нет автобокса. Фактически, учитывая:
public static void requireInRange(int index, Object[] array) {
...
}
int[] anArray = {3, 4, 2};
requireInRange(3, anArray); // DOES NOT COMPILE!!!
В то время как int
может быть автоматически упакован в Целое число
, int []
не будет автоматически упакован НЕ to Integer []
от Java. Для этого вы можете написать библиотечные функции, но язык не облегчит это преобразование.
Это на самом деле источник многих недоразумений, например, относительно Arrays.asList (anIntArray)
«сломан», потому что вместо возврата List
, то, что возвращается, фактически является одноэлементным List
.
Цитата из Java Language Guide / Autoboxing :
Неуместно использовать автобоксирование и распаковку для научных вычислений или других числовых вычислений, зависящих от производительности. код.
Целое число
не заменяетint
; автобоксирование и распаковка стирают различие между примитивными типами и ссылочными типами, но не устраняют его.
Короче говоря, всякий раз, когда происходит автобокс, производительность определенно сильно страдает.Некоторые вещи помогают облегчить это, например механизм кэширования, встроенный в эти типы. Вот почему вы получаете следующее:
System.out.println(
((Integer) 0) == ((Integer) 0)
);
// true
System.out.println(
((Integer) 10000) == ((Integer) 10000)
);
// false (implementation-specific)
Здесь произошло следующее: когда 0
автоматически помещается в штучную упаковку, фактически не создается экземпляр new Integer
: значения в определенном диапазоне кэшируются для целей автобокса, чтобы повысить производительность. 10000
в большинстве реализаций, вероятно, выпадает из этого диапазона, но некоторые реализации JVM позволяют при необходимости указывать диапазон кеширования.
Есть много способов упростить requireInRange
работу с любыми типами массивов. К сожалению, работа с массивом примитивов Java часто требует большого количества повторений. Это означает предоставление перегрузок для int []
, логического []
, байта []
, объекта []
и т. Д. Отдельно.
Более лаконичный вариант - использовать отражение, но в этом есть свои плюсы и минусы. Вообще говоря, отражение не должно быть предпочтительным решением для большинства сценариев.
Сказав это, java.lang.reflect.Array
действительно имеет метод int getLength (Object array)
static
, который может возвращать длину ЛЮБОГО массив. Это не типобезопасно (как и большинство механизмов отражения); передача не-массива компилируется, но вызывает исключение IllegalArgumentException
во время выполнения.
java.util.Массивы
) Будет ли компилятор вставлять код на самом деле для упаковки каждого значения массива?
Компилятор отклонит код, потому что int []
не может быть передано в метод, который принимает параметр Object []
.
Автобоксирование выполняется только для отдельных примитивных значений, а не для целых массивов.
Если есть сомнения, вы можете предположить, что компилятор не оптимизирует код. Обычно это дословный перевод кода.
Кроме того, если вы сомневаетесь, вы можете предположить, что JVM очень хорошо справляется с оптимизацией кода во время выполнения. Я бы не стал думать, что это имеет значение, если у вас нет веских оснований (например, профилировщика) подозревать, что это проблема.