Влияние на производительность автобокса - PullRequest
12 голосов
/ 07 августа 2010

Обычно компилятор генерирует код для выполнения упаковки и распаковки. Но что делает компилятор, если коробочные значения не нужны? Компилятор (стандарт 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);

Будет ли компилятор вставлять код для упаковки каждого значения массива?

Ответы [ 3 ]

39 голосов
/ 07 августа 2010

В вашем коде нет автобокса.Фактически, учитывая:

public static void requireInRange(int index, Object[] array) {
   ...
}

int[] anArray = {3, 4, 2};
requireInRange(3, anArray); // DOES NOT COMPILE!!!

В то время как int может быть автоматически упакован в Integer, int[] делает НЕ автоматически помещенным в Integer[] Java.Вы можете написать библиотечные функции, чтобы сделать это, но язык не облегчит это преобразование.

Это на самом деле источник многих недоразумений, например, о том, что Arrays.asList(anIntArray) «сломан», потому что вместо возврата List<Integer> то, что возвращается, на самом деле является одним элементом List<int[]>.


А как насчет производительности ???

Цитата из Руководство по языку Java / Автобокс :

Не рекомендуется использовать автобокс и распаковку для научных вычислений или другой числовой код, чувствительный к производительности.Integer не является заменой 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[], boolean[], byte[], Object[] и т. Д.

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

Сказав, что java.lang.reflect.Array имеет int getLength(Object array) static метод, которыйможет вернуть длину массива ANY .Это небезопасно (как большинство механизмов отражения);передает компиляцию без массива, но выдает IllegalArgumentException во время выполнения.

Смежные вопросы

2 голосов
/ 07 августа 2010

Если вы сомневаетесь, вы можете предположить, что компилятор не оптимизирует код.Обычно он выполняет буквальный перевод кода.

Кроме того, если вы сомневаетесь, что JVM очень хорошо оптимизирует код во время выполнения.Я не думаю, что это имеет какое-то значение, если у вас нет веских причин (таких как профилировщик) подозревать, что это проблема.

2 голосов
/ 07 августа 2010

Будет ли компилятор вставлять код для бокса каждое значение массива?

Компилятор отклонит код, потому что int[] нельзя передать в метод, который принимает параметр Object[].

Автобокс происходит только для отдельных значений примитивов, но не для целых массивов.

...