ArrayList: как увеличивается размер?

48

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

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

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

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

  • 1
    Лучший способ узнать это - прочитать исходный код. Но будьте осторожны. Здесь будут драконы.
  • 1
    Вот источник ArrayList из OpenJDK 6. Имейте в виду, что существует множество его реализаций (GNU Classpath, Apache Harmony, OpenJDK, ...), и они могут отличаться.
Показать ещё 1 комментарий
Теги:
arrays
arraylist
collections

13 ответов

38
Лучший ответ

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

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

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

  • 0
    Будет создан новый массив, а содержимое старого будет скопировано. так что будет со старым массивом, он будет в памяти или удален?
  • 1
    @VikasKumarSingh: старый получает право на сборку мусора, как и любой объект, на который больше нет ссылок. Когда (или даже если) это происходит, зависит от JVM.
Показать ещё 4 комментария
26

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

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

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

24

Sun JDK6:

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

int newCapacity then = 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.

EDIT: для тех, кто не понял, какая связь между множителем 1.5 и int newCapacity = oldCapacity + (oldCapacity >> 1);

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

  • 1
    Это правильный ответ !!! Хорошая работа @mgmiller
  • 1
    да, чтение исходного кода - лучший способ понять поведение. Я также прочитал код и получил тот же ответ. Это верно для JDK 8.
7

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

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

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

Изображение 118753

Изображение 118754

Edit:

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

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

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

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

Используя следующую формулу:

  int newCapacity= (oldCapacity * 3)/2 +1;
  • 5
    это движение :), когда вы получите свой ответ в поиске Google спустя почти 2 года
5

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

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

i.e OldCapacity * 3/2 + 1 = 10 * 3/2 + 1 = 16

3

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

1

Контекст 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);
    }

key code - это строка:

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

Таким образом, фактор роста также равен 1.5, так же как java 6.

  • 3
    Для людей, которые не могут получить деривацию для «1,5». Рассматривая oldCapacity как x, тогда newCapacity = x + x / (2 ^ 1) = x + x / 2 = 1.5x
  • 1
    Оператор «>>», который подписывает расширение во время сдвига, может немного сбивать с толку некоторых, поскольку он не считается используемым в качестве оператора div из-за отсутствия работы с отрицательными значениями. В этом случае это просто работает, потому что длина всегда> = 0. В качестве оператора div следует использовать преимущественно >>>.
0

Значение по умолчанию для ArrayList равно 10. Как только емкость достигнет максимальной емкости, размер массива ArrayList будет равен 16, как только емкость достигнет максимальной емкости 16, размер ArrayList составит 25 и будет увеличиваться в зависимости от размера данных.....

Как? Вот ответ и формула

New capacity = (Current Capacity * 3/2) + 1

Итак, если значение по умолчанию равно 10, то

Current Capacity = 10
New capacity = (10 * 3/2) + 1
Output is 16
0

Размер ArrayList всегда увеличивается с n+n/2+1.

  • 1
    Можете ли вы добавить некоторые объяснения? это довольно короткий
0

Когда 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;

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

0

Контекст: JDK 7

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

public boolean add(E paramE) {
        ensureCapacityInternal(this.size + 1);
        this.elementData[(this.size++)] = paramE;
        return true;
    }

private void ensureCapacityInternal(int paramInt) {
        if (this.elementData == EMPTY_ELEMENTDATA)
            paramInt = Math.max(10, paramInt);
        ensureExplicitCapacity(paramInt);
    }
private void ensureExplicitCapacity(int paramInt) {
        this.modCount += 1;
        if (paramInt - this.elementData.length <= 0)
            return;
        grow(paramInt);
    }

private void grow(int paramInt) {
    int i = this.elementData.length;
    int j = i + (i >> 1);
    if (j - paramInt < 0)
        j = paramInt;
    if (j - 2147483639 > 0)
        j = hugeCapacity(paramInt);
    this.elementData = Arrays.copyOf(this.elementData, j);
}
0

Что происходит с новым массивом, созданным с пробелами n * 2, тогда все элементы в старом массиве копируются и новый элемент вставляется в первое свободное пространство. В общем, это приводит к тому, что O (N) добавляет время для ArrayList.

Если вы используете Eclipse, установите Jad и Jadclipse, чтобы декомпилировать JAR, хранящиеся в библиотеке. Я сделал это, чтобы прочитать исходный код.

-1

Размер по умолчанию для arraylist равен 10. Когда мы добавляем 11-й... arraylist увеличивает размер (n * 2). Значения, хранящиеся в старых arraylist, копируются в новый arraylist, размер которого равен 20.

  • 0
    Это не добавляет ничего, что не было сказано в первоначальных ответах 2010 года.
  • 0
    При добавлении 11-го элемента вместимость будет 15, а не 20.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню