Что использование кода в реализации AbstractCollection toArray Method
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
Ну, метод javadoc sais все:
/**
* {@inheritDoc}
*
* <p>This implementation returns an array containing all the elements
* returned by this collection 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();
* }</pre>
*/
Я нахожу здесь две интересные вещи:
-
Да, вы правы, так как javadoc sais, этот метод готов к возврату корректно, даже если коллекция была изменена в среднем. Вот почему первоначальный размер - всего лишь намек. Использование итератора также обеспечивает исключение из исключения "параллельной модификации".
-
Очень легко представить многопоточную ситуацию, когда один поток добавляет/удаляет элементы из коллекции, в то время как другой поток вызывает метод toArray на нем. В такой ситуации, если сборка не является потокобезопасной (например, полученная с помощью метода Collections.synchronizedCollection(...)
или вручную создавая синхронизированный код доступа к ней), вы попадаете в ситуацию, когда она модифицируется и одновременно изменяется.
Ответ 2
Я просто хочу упомянуть, что в соответствии с javadoc метод size()
может возвращать максимум Integer.MAX_VALUE. Но если ваша коллекция содержит больше элементов, вы не можете получить нужный размер.
Ответ 3
вы правы, массив инициализируется с помощью size(), поэтому, если какой-либо элемент удаляется во время заполнения массива, вы можете воспользоваться этой проверкой.
Коллекции по умолчанию не являются потокобезопасными, поэтому другой поток может вызвать remove(), пока выполняется итерация: -)
Ответ 4
В то время как в целом он гарантирован (например, для всех классов java.util. *), что коллекция не будет изменяться во время итерации (в противном случае возникает исключение ConcurrentModificationException), это не гарантируется для всех коллекций. Поэтому для другого потока можно добавить или удалить элементы, в то время как один поток вызывает toArray(), тем самым изменяя размер коллекции и, следовательно, результирующий массив. В качестве альтернативы, некоторые реализации могут возвращать приблизительный размер.
Поэтому, чтобы ответить на вопрос:
-
Эти две строки проверяют, был ли достигнут конец коллекции до ожидаемого размера (результат вызова size(), который определяет r.length). Если это так, будет сделана копия массива r с соответствующим размером. Помните, что невозможно изменить размер массива.
-
Как сказано, разные возможности, так как контракт на коллекцию довольно свободен. Многопоточность, приблизительные результаты по размеру() и другие.
Ответ 5
Андрей - главный ответ. corsair дает отличную оценку Integer.MAX_VALUE.
Для полноты я добавлю, что метод toArray должен работать в любой коллекции, включая:
- массивы с использованием метода багги;
-
динамические массивы - содержимое коллекции может меняться в зависимости от других потоков (concurrency), времени или случайных чисел. Пример в псевдокоде
Продукты питания > thingsACatholicCanEat;//если в пятницу не следует включать мясо