ArrayList: как увеличивается размер? - PullRequest
63 голосов
/ 15 декабря 2010

У меня есть основной вопрос по Java ArrayList.

Когда ArrayList объявляется и инициализируется с использованием конструктора по умолчанию, создается пространство памяти для 10 элементов. Теперь, когда я добавляю 11-й элемент, что происходит? Будет ли создано новое пространство памяти с емкостью 20 (или более) элементов (для этого необходимо скопировать элементы из первой ячейки памяти в новую ячейку) ИЛИ что-нибудь еще?

Я проверил здесь . Но я не нашел ответа.

Пожалуйста, поделитесь знаниями. Спасибо.

Ответы [ 17 ]

46 голосов
/ 15 декабря 2010

Создается новый массив, а содержимое старого копируется. Это все, что вы знаете на уровне API. Цитата из документов (мой акцент):

Каждый экземпляр ArrayList имеет емкость. Емкость - это размер массива, используемого для хранения элементов в списке. Это всегда как минимум размер списка. Когда элементы добавляются в ArrayList, его емкость увеличивается автоматически. Подробности политики роста не указаны за исключением того факта, что добавление элемента имеет постоянные амортизированные временные затраты.

С точки зрения того, как это на самом деле происходит с конкретной реализацией ArrayList (например, Sun), в их случае вы можете увидеть мрачные детали в источнике. Но, конечно, полагаться на детали конкретной реализации обычно не очень хорошая идея ...

34 голосов
/ 03 января 2013

Sun's JDK6:

Я считаю, что оно увеличивается до 15 элементов. Не кодирую это, но смотрю на расти () код в JDK.

int newCapacity затем = 10 + (10 >> 1) = 15.

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

В Javadoc говорится, что это из Java 2 и далее, так что это безопасная ставка в Sun JDK.

РЕДАКТИРОВАТЬ : для тех, кто не понял, какая связь между множителем 1.5 и int newCapacity = oldCapacity + (oldCapacity >> 1);

>> - оператор сдвига вправо, который уменьшает число до половины. Таким образом,
int newCapacity = oldCapacity + (oldCapacity >> 1);
=> int newCapacity = oldCapacity + 0.5*oldCapacity;
=> int newCapacity = 1.5*oldCapacity ;

28 голосов
/ 15 декабря 2010

Это будет зависеть от реализации, но от исходного кода Sun Java 6:

int newCapacity = (oldCapacity * 3)/2 + 1;

Это в методе ensureCapacity. Другие реализации JDK могут отличаться.

11 голосов
/ 10 сентября 2014

Когда мы пытаемся добавить объект в массив,

Java проверяет , чтобы убедиться, что в существующем массиве достаточно места для размещения нового объекта.Если нет, то создается новый массив большего размера , старый массив копируется в новый массив с использованием Arrays.copyOf , и новый массив присваиваетсясуществующий массив.

Посмотрите на код ниже (взято из Java ArrayList Code на GrepCode.com).

Check this example

enter image description here

Редактировать:

public ArrayList () Создает пустой список с начальной емкостью 10.

public ArrayList (int initialCapacity) мы можем указать начальную емкость.

public ArrayList (Collection c) Создает список, содержащий элементы указанной коллекции, в том порядке, в котором они возвращаются итератором коллекции.

Теперь, когда мы используем конструктор ArrayList (), мы получаем ArrayList с Size = 10 При добавлении 11-го элемента в списке новый метод Arraylist создается внутри метода sureCapacity ().

Использование следующей формулы:

  int newCapacity= (oldCapacity * 3)/2 +1;
6 голосов
/ 08 ноября 2012

когда ArrayList объявлен и инициализирован с использованием конструктора по умолчанию, будет создано пространство памяти для 10 элементов.теперь, когда я добавляю 11-й элемент,

ArrayList создает новый объект со следующим размером

т.е. OldCapacity * 3/2 + 1 = 10 * 3/2 + 1 =16

4 голосов
/ 15 декабря 2010

Как правило, память для контейнеров типа ArrayList увеличивается путем удвоения ее. Таким образом, если у вас изначально было место для 10 элементов и вы добавили 10, одиннадцатый элемент будет добавлен в новый (внутренний) массив из 20 элементов. Причиной этого является то, что дополнительные затраты на добавление элементов уменьшаются с O (n ^ 2), если массив увеличивался с шагом фиксированного размера, до хорошего O (n) при удвоении размера при каждом заполнении внутреннего массива.

4 голосов
/ 16 сентября 2018

До JDK 6 емкость увеличивается с формулой newCapacity = (oldCapacity * 3/2) + 1.

В JDK 7 и выше формула меняется на newCapacity = oldCapacity + (oldCapacity >> 1).

Так, если начальная емкость равна 10, то новая емкость будет 16 in JDK6 и 15 in above JDK6

3 голосов
/ 26 октября 2016

Контекст java 8

Я даю свой ответ здесь в контексте реализации Oracle java 8, так как после прочтения всех ответов я обнаружил, что ответ в контексте java 6дал gmgmiller, а другой ответ был дан в контексте Java 7. Но как Java 8 реализует увеличение размера не было дано.

В java 8 поведение при увеличении размера такое же, как и в java 6, см. Метод grow ArrayList:

   private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

код ключа - эта строка:

int newCapacity = oldCapacity + (oldCapacity >> 1);

Итак, фактор роста также равен 1,5, как и в случае с Java 6.

2 голосов
/ 25 августа 2018

Давайте посмотрим на этот код (jdk1.8)

@Test
    public void testArraySize() throws Exception {
        List<String> list = new ArrayList<>();
        list.add("ds");
        list.add("cx");
        list.add("cx");
        list.add("ww");
        list.add("ds");
        list.add("cx");
        list.add("cx");
        list.add("ww");
        list.add("ds");
        list.add("cx");
        list.add("last");
    }

1) Поместите точку останова в строку, когда вставлено «последнее»

2) Перейти к методу добавления ArrayList Вы увидите

ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;

3) Перейдите к методу ОбеспечитьCapacityInternal, вызов этого метода ensureExplicitCapacity

4)

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
            return true;

В нашем примере minCapacity равен 11 11-10 > 0, поэтому вам необходим grow метод

5)

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

Давайте опишем каждый шаг:

1) oldCapacity = 10, поскольку мы не указали этот параметр при инициализации ArrayList, поэтому он будет использовать емкость по умолчанию (10)

2) int newCapacity = oldCapacity + (oldCapacity >> 1); Здесь newCapacity равен oldCapacity плюс oldCapacity со смещением вправо на единицу (oldCapacity is 10 это двоичное представление 00001010, сдвинув его на один бит вправо, мы получим 00000101, что равно 5 в десятичном выражении, поэтому newCapacity равно 10 + 5 = 15)

3)

if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;

Например, ваша емкость инициализации равна 1, когда вы добавите второй элемент в arrayList newCapacity будет равно 1(oldCapacity) + 0 (moved to right by one bit) = 1 В этом случае newCapacity меньше minCapacity и elementData (объект массива внутри arrayList) не может содержать новый элемент, поэтому newCapacity равен minCapacity

4)

if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);

Проверьте, не достигает ли размер массива MAX_ARRAY_SIZE (который равен Integer.MAX - 8) Почему максимальный размер массива ArrayList равен Integer.MAX_VALUE - 8?

5) Наконец, он копирует старые значения в newArray длиной 15

2 голосов
/ 14 ноября 2016

Когда ArrayList объявлен и инициализирован с использованием конструктора по умолчанию, создается пространство памяти для 10 элементов.

НЕТ.Когда ArrayList инициализируется, выделение памяти производится для пустого массива.Выделение памяти для емкости по умолчанию (10) производится только после добавления первого элемента в ArrayList.

 /**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
 * DEFAULT_CAPACITY when the first element is added.
 */
private transient Object[] elementData;

PS Не хватает репутации, чтобы комментировать вопрос, поэтому я ставлю это как ответ, поскольку никтоуказал на это неверное предположение ранее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...