Является ArrayList.size () кэшируемым методом?

Я задавался вопросом, size() метод, что можно обратиться к существующему ArrayList<T> кэшируемый? Или действительно ли это предпочтительно в производительности критический код, который я просто храню size() в локальном интервале?

Я ожидал бы, что это действительно кэшируется, когда Вы не добавляете/удаляете объекты между вызовами к size().

Я прав?

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

18
задан Peterdk 18 May 2010 в 12:23
поделиться

7 ответов

Я бы не сказал, что это "кэшируется" как таковое - но это просто хранится в поле, так что это достаточно быстро для частого вызова.

Реализация size() в Sun JDK выглядит так:

public int size() {
    return size;
}
13
ответ дан 30 November 2019 в 08:47
поделиться

Очевидной реализацией ArrayList было бы внутреннее сохранение размера в поле. Я был бы очень удивлен, если бы его когда-нибудь нужно было вычислить, даже после изменения размера.

0
ответ дан 30 November 2019 в 08:47
поделиться

Почему это должно быть так? ArrayList реализует интерфейс List, который поддерживается массивом, в конце концов.

Я бы предположил, что у него просто есть член size, который увеличивается при вставке и уменьшается при удалении, а затем он просто возвращает его.

Хотя я не смотрел больше, чем API-документы.

0
ответ дан 30 November 2019 в 08:47
поделиться

Если кэширование результата метода size () заметно повысит производительность (что это иногда случается - я регулярно вижу ArrayList.size () как лучший скомпилированный метод в моем выводе -Xprof ), а затем рассматриваю возможность преобразования всего списка в массив для еще большего ускорения.

Вот один прием, который может сработать, если вы регулярно просматриваете список, но редко его обновляете:

class FooProcessor {

    private Foo[] fooArray = null;
    private List<Foo> fooList = new ArrayList<Foo>();

    public void addFoo(Foo foo) {
       fooList.add(foo);
       fooArray = null;
    }

    public void processAllFoos() {
        Foo[] foos = getFooArray();
        for (int i = 0; i < foos.length; ++ i) {
            process(foos[i]);
        }
    }

    private void getFooArray() {
        if (fooArray == null) {
            Foo[] tmpArray = new Foo[fooList.size()];
            fooArray = fooList.toArray(tmpArray);
        }
        return fooArray;
    }

}
0
ответ дан 30 November 2019 в 08:47
поделиться

Да.

Быстрый взгляд на исходный текст Java подскажет вам ответ.

5
ответ дан 30 November 2019 в 08:47
поделиться

Это реализация в OpenJDK версии:

/**
 * Returns the number of elements in this list.
 *
 * @return the number of elements in this list
 */
public int size() {
    return size;
}

Так что это настолько хорошо, насколько может быть хорош вызов метода. Маловероятно, что HotSpot кэширует значение, возвращаемое этим методом, так что если вы действительно ТАК обеспокоены, вы можете кэшировать его самостоятельно. Если только профилирование не показало, что это узкое место (что маловероятно), вам следует беспокоиться о читабельности, а не о том, кэшируется или нет простой вызов метода, возвращающий значение поля.

2
ответ дан 30 November 2019 в 08:47
поделиться

Я не знаю ответа наверняка, но мое предположение: нет. У компилятора Java нет никакого способа, кроме специальной оболочки ArrayList, узнать, что вызываемые вами функции не будут мутирующими и что в результате вызов size() должен вернуть одно и то же значение. Поэтому я считаю маловероятным, что компилятор Java будет учитывать повторные вызовы size() и хранить их во временном значении. Если вам нужен такой уровень оптимизации, тогда вы должны сами хранить значение в локальной переменной. В противном случае, да, вы будете платить за накладные расходы на вызов функции, связанные с вызовом метода size(). Заметьте, однако, что метод size() является O(1) для ArrayList (хотя накладные расходы на вызов функции довольно велики). Лично я бы исключил все вызовы size() из циклов и вручную сохранял бы их в локале там, где это необходимо.

Редактировать
Хотя такая оптимизация не может быть выполнена компилятором Java, было верно подмечено, что JIT может инлайнить реализацию ArrayList.size() так, что это будет стоить столько же, сколько обращение к полю, без дополнительных накладных расходов на вызов метода, так что в действительности расходы пренебрежимо малы, хотя вы все равно можете немного сэкономить, сохраняя вручную во временной памяти (что потенциально может исключить поиск в памяти и вместо этого обслуживать переменную из регистра процессора).

2
ответ дан 30 November 2019 в 08:47
поделиться
Другие вопросы по тегам:

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