Технически это 10
не ноль, если допустить ленивую инициализацию резервного массива. Увидеть:
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
где
private static final int DEFAULT_CAPACITY = 10;
Вы имеете в виду только начальный объект массива нулевого размера, который используется совместно всеми изначально пустыми ArrayList
объектами. Т.е. производительность 10
гарантируется лениво , оптимизация присутствует и в Java 7.
По общему признанию, контракт конструктора не совсем точен. Возможно, в этом и есть источник путаницы.
Задний план
Вот электронное письмо Майка Дуигу
Я разместил обновленную версию пустого патча ArrayList и HashMap.
http://cr.openjdk.java.net/~mduigou/JDK-7143928/1/webrev/
Эта переработанная реализация не вводит новых полей ни в один из классов. Для ArrayList ленивое выделение резервного массива происходит только в том случае, если список создается с размером по умолчанию. По данным нашей группы анализа производительности, примерно 85% экземпляров ArrayList создаются с размером по умолчанию, поэтому такая оптимизация будет действительна в подавляющем большинстве случаев.
Для HashMap творчески используется поле порога для отслеживания запрошенного начального размера до тех пор, пока не понадобится массив сегментов. На стороне чтения пустая карта проверяется с помощью isEmpty (). По размеру записи сравнение (table == EMPTY_TABLE) используется для определения необходимости раздувания массива корзин. В readObject есть еще немного работы, чтобы попытаться выбрать эффективную начальную емкость.
От: http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-April/015585.html
getCapacity()
метода или чего-то подобного. (Тем не менее, что-то вродеensureCapacity(7)
запрета для инициализированного по умолчанию ArrayList, поэтому я предполагаю, что мы действительно должны действовать так, как если бы его первоначальная емкость была действительно 10 ...)ArrayList
созданный конструктором без аргументов, а не передаете конструктору нольint
, и если вы смотрите на размер внутреннего массива рефлексивно или в отладчике. В случае по умолчанию длина массива изменяется от 0 до 10, затем до 15, 22, следуя скорости роста в 1,5 раза. Нулевое значение начальной емкости приводит к росту с 0 до 1, 2, 3, 4, 6, 9, 13, 19 ....emptyList()
прежнему потребляет меньше памяти, чем несколько пустыхArrayList
экземпляров. Сейчас это менее важно и, следовательно, не нужно везде , особенно в местах с более высокой вероятностью добавления элементов в более позднее время. Также имейте в виду, что иногда вам нужен неизменяемый пустой список, и тогда это лучший вариантemptyList()
.В java 8 емкость ArrayList по умолчанию равна 0, пока мы не добавим хотя бы один объект в объект ArrayList (вы можете назвать это ленивой инициализацией).
Теперь вопрос в том, почему это изменение было сделано в JAVA 8?
Ответ - для экономии потребления памяти. Миллионы объектов списков массивов создаются в Java-приложениях в реальном времени. Размер по умолчанию 10 объектов означает, что мы выделяем 10 указателей (40 или 80 байтов) для базового массива при создании и заполняем их нулями. Пустой массив (заполненный нулями) занимает много памяти.
Ленивая инициализация откладывает это потребление памяти до того момента, когда вы действительно будете использовать список массивов.
Пожалуйста, смотрите код ниже для получения помощи.
ArrayList al = new ArrayList(); //Size: 0, Capacity: 0 ArrayList al = new ArrayList(5); //Size: 0, Capacity: 5 ArrayList al = new ArrayList(new ArrayList(5)); //Size: 0, Capacity: 0 al.add( "shailesh" ); //Size: 1, Capacity: 10 public static void main( String[] args ) throws Exception { ArrayList al = new ArrayList(); getCapacity( al ); al.add( "shailesh" ); getCapacity( al ); } static void getCapacity( ArrayList<?> l ) throws Exception { Field dataField = ArrayList.class.getDeclaredField( "elementData" ); dataField.setAccessible( true ); System.out.format( "Size: %2d, Capacity: %2d%n", l.size(), ( (Object[]) dataField.get( l ) ).length ); } Response: - Size: 0, Capacity: 0 Size: 1, Capacity: 10
В статье « Емкость по умолчанию для ArrayList в Java 8» это подробно объясняется.
источник
Если самой первой операцией, выполняемой с ArrayList, является передача
addAll
коллекции, содержащей более десяти элементов, то любые усилия, приложенные для создания исходного массива из десяти элементов для хранения содержимого ArrayList, будут выброшены из окна. Каждый раз, когда что-то добавляется в ArrayList, необходимо проверить, не превышает ли размер результирующего списка размер резервного хранилища; разрешение начальному резервному хранилищу иметь размер ноль, а не десять, приведет к тому, что этот тест потерпит неудачу еще один раз за время существования списка, первой операцией которого является «добавление», что потребует создания исходного массива из десяти элементов, но эта стоимость составляет меньше, чем стоимость создания массива из десяти элементов, который никогда не будет использоваться.При этом в некоторых контекстах можно было бы дополнительно улучшить производительность, если бы была перегрузка addAll, в которой указывалось, сколько элементов (если есть), вероятно, будет добавлено в список после текущего, а какие могут используйте это, чтобы повлиять на его поведение распределения. В некоторых случаях код, который добавляет последние несколько элементов в список, будет иметь довольно хорошее представление о том, что списку никогда не понадобится дополнительное пространство. Есть много ситуаций, когда список заполняется один раз и больше не изменяется. Если в точке кода известно, что конечный размер списка будет 170 элементов, у него будет 150 элементов и резервное хранилище размером 160,
источник
addAll()
. Это еще одна возможность повысить эффективность работы с первым malloc.Вопрос в том «почему?».
Проверки профилирования памяти (например ( https://www.yourkit.com/docs/java/help/inspections_mem.jsp#sparse_arrays ) показывают, что пустые (заполненные нулями) массивы занимают тонны памяти.
Размер по умолчанию 10 объектов означает, что мы выделяем 10 указателей (40 или 80 байтов) для базового массива при создании и заполняем их нулями. Настоящие java-приложения создают миллионы списков массивов.
Введенная модификация удаляет ^ W, откладывает это потребление памяти до того момента, когда вы действительно будете использовать список массивов.
источник
После вышеупомянутого вопроса я просмотрел документ ArrayList для Java 8. Я обнаружил, что размер по умолчанию по-прежнему равен 10.
источник
Размер ArrayList по умолчанию в JAVA 8 равен 10. Единственное изменение, внесенное в JAVA 8, состоит в том, что если кодировщик добавляет элементов меньше 10, то оставшиеся пустые места в arrayylist не задаются равными нулю. Сказав так, потому что я сам прошел через эту ситуацию, и затмение заставило меня взглянуть на это изменение JAVA 8.
Вы можете обосновать это изменение, посмотрев на скриншот ниже. В нем вы можете видеть, что размер ArrayList указан как 10 в Object [10], но количество отображаемых элементов составляет всего 7. Остальные элементы с нулевым значением здесь не отображаются. В JAVA 7 ниже снимок экрана такой же, с одним изменением, которое заключается в том, что также отображаются элементы нулевого значения, для которых кодировщику необходимо написать код для обработки нулевых значений, если он выполняет итерацию полного списка массивов, в то время как в JAVA 8 это бремя снимается с руководитель кодера / разработчика.
Ссылка на скриншот.
источник