что такое использование кода в реализации метода toArray AbstractCollection - PullRequest
11 голосов
/ 06 декабря 2011
public Object[] toArray() {
    // Estimate size of array; be prepared to see more or fewer elements
    Object[] r = new Object[size()];
    Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        if (! it.hasNext()) // fewer elements than expected
            return Arrays.copyOf(r, i);
        r[i] = it.next();
    }
    return it.hasNext() ? finishToArray(r, it) : r;
}

вот код реализации метода AbstractCollection.toArray.

if (! it.hasNext()) // fewer elements than expected
    return Arrays.copyOf(r, i);

Я не понимаю использование кода выше. Я подозреваю, что код используется, чтобы избежать изменения размера при вызове метода. Итак, у меня есть два вопроса:

  1. Что я подозреваю, правильно или неправильно? если это не так, то как используется этот код?
  2. Если это правда, то какая ситуация может привести к изменению размера при вызове метода?

Ответы [ 5 ]

6 голосов
/ 06 декабря 2011

Ну, в методе javadoc все сказано:

<code> /**
     * {@inheritDoc}
     *
     * <p>This implementation returns an array containing all the elements
     * returned by this collection's iterator, in the same order, stored in
     * consecutive elements of the array, starting with index {@code 0}.
     * The length of the returned array is equal to the number of elements
     * returned by the iterator, even if the size of this collection changes
     * during iteration, as might happen if the collection permits
     * concurrent modification during iteration.  The {@code size} method is
     * called only as an optimization hint; the correct result is returned
     * even if the iterator returns a different number of elements.
     *
     * <p>This method is equivalent to:
     *
     *  <pre> {@code
     * List<E> list = new ArrayList<E>(size());
     * for (E e : this)
     *     list.add(e);
     * return list.toArray();
     * }
* /

Здесь я нахожу две интересные вещи:

  1. Да, вы правы, как говорит javadoc, этот метод готов правильно вернуться, даже если коллекция была изменена за это время.Вот почему начальный размер просто подсказка.Использование итератора также позволяет избежать исключения «параллельная модификация».

  2. Очень легко представить многопоточную ситуацию, когда один поток добавляет / удаляет элементы из коллекции, в то время какдругой поток вызывает метод toArray.В такой ситуации, если коллекция не является поточно-ориентированной (например, полученной с помощью метода Collections.synchronizedCollection(...) или путем ручного создания синхронизированного кода доступа к ней), вы попадете в ситуацию, когда она модифицируется и одновременно обрабатывается массивом.

3 голосов
/ 06 декабря 2011

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

0 голосов
/ 06 декабря 2011

Андрей - главный ответ. corsair поднимает отличную мысль о Integer.MAX_VALUE.

Для полноты картины я добавлю метод toArray, который должен работать с любой коллекцией, включая:

  1. массивы с ошибочным методом размера;
  2. динамические массивы - содержимое Коллекции может изменяться в зависимости от других потоков (параллелизма), времени или случайных чисел. Пример в псевдокоде

    Коллекция вещейACatholicCanEat; // если это пятница, не следует включать мясо

0 голосов
/ 06 декабря 2011

Хотя обычно гарантируется (например, для всех классов коллекции java.util. *), Что коллекция не изменится, пока она повторяется (в противном случае создается исключение ConcurrentModificationException), это не гарантируется для всех коллекций.Поэтому другой поток может добавлять или удалять элементы, в то время как один поток вызывает toArray (), тем самым изменяя размер коллекции и, следовательно, результирующий массив.В качестве альтернативы, некоторые реализации могут возвращать только приблизительный размер.

Поэтому, чтобы ответить на вопрос:

  1. Эти две строки проверяют, был ли достигнут конец коллекции до того, какожидаемый размер (результат вызова size (), который определяет r.length) был достигнут.Если это так, будет сделана копия массива r с соответствующим размером.Помните, что невозможно изменить размер массива.

  2. Как уже говорилось, различные возможности, так как контракт на Collection является довольно свободным.Многопоточность, приблизительные результаты по размеру () и другие.

0 голосов
/ 06 декабря 2011

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

Коллекции по умолчанию не являются потокобезопасными, поэтому другой поток может вызвать remove () во время выполнения итерации: -)

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