it-roy-ru.com

Различие между емкостью списка массивов и размером массива

Я прочитал приведенный ниже фрагмент в книге Core Java I.

Выделение списка массивов как новый ArrayList <'Employee> (100) // емкость равна 100

не то же самое, что выделение нового массива как новый сотрудник [100] // размер 100

Существует важное различие между емкостью списка массивов и размером массив. Если вы выделите массив из 100 записей, то массив будет иметь 100 слотов, готовых к использованию . Список массивов с емкостью 100 элементов может содержать 100 элементов (и, фактически, более 100, за счет дополнительных перераспределений); но в начале, даже после своей первоначальной конструкции список массивов вообще не содержит элементов.

Когда я увидел список массивов исходного кода, конструктор создает массив объектов заданной емкости, который готов содержать элементы заданной емкости (ниже приведен фрагмент кода). 

public ArrayList(int initialCapacity) {
     super();
     if (initialCapacity < 0)
         throw new IllegalArgumentException("Illegal Capacity: "+
                                            initialCapacity);
     this.elementData = new Object[initialCapacity];
 }

Я не могу выяснить фактическую разницу, что автор упомянул в приведенном выше тексте. 

14
Kumar V

Если вы выделите новый массив с помощью arr = new Employee[100], размер этого массива (arr.length) будет равен 100. Он имеет 100 элементов. Все элементы изначально равны нулю (так как это массив ссылок на объекты), но все же есть 100 элементов.

Если вы сделаете что-то вроде list = new ArrayList <Employee>(100) и попытаетесь проверить list.size(), вы получите 0. В списке нет элементов.

Внутренне, это правда, что ArrayList выделяет достаточно места для размещения 100 элементов, прежде чем ему нужно будет расширить свою емкость, но это внутренняя деталь реализации, и список представляет вам свое содержимое как «элементы не сохранены». Только если вы на самом деле делаете list.add(something), у вас будут элементы в списке.

Таким образом, хотя список выделяет хранилище заранее, API, с которым он связывается с программой, сообщает, что в нем нет элементов. Нулевые элементы в его внутреннем массиве недоступны для вас - вы не можете получить их или изменить.

26
RealSkeptic

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

ArrayList хранит элементы списка, используя фактический массив «под крышками». Реальная реализация массива в памяти компьютера имеет определенный размер при выделении; этот размер - вместимость ArrayList. ArrayList эмулирует список переменного размера, сохраняя логическую длину списка в дополнение к массиву фиксированной длины. Таким образом, если у вас есть ArrayList с емкостью 10, который содержит 4 логических элемента, ArrayList может быть представлен как длина и массив

(4) | е1 | е2 | е3 | е4 | __ | __ | __ | __ | __ | __ |

где (4) - логическая длина списка, а __ - данные, которые игнорируются, поскольку они не являются частью логического списка. Если вы попытаетесь получить доступ к 5-му элементу этого ArrayList, он выдаст исключение, потому что знает, что пятый элемент не был инициализирован. Если затем мы добавим дополнительный элемент e5 в список, ArrayList станет

(5) | е1 | е2 | е3 | е4 | е5 | __ | __ | __ | __ | __ |

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

Если вам удастся добавить более десяти элементов в этот список, ArrayList не сломается. ArrayList - это абстракция, предназначенная для совместимости со всеми операциями с массивами. Скорее ArrayList меняет свою емкость, когда его логическая длина превышает его первоначальную емкость. Если бы мы добавили элементы (a1, a2, ..., a7) в вышеприведенный список, результирующий ArrayList мог бы выглядеть следующим образом

(12) | е1 | е2 | е3 | е4 | е5 | а1 | а2 | а3 | а4 | а5 | а6 | а7 | __ | __ | __ | __ | __ | __ | __ | __ |

вместимостью 20 чел.

Создав ArrayList, вы можете игнорировать емкость во всех следующих программах; логика не затронута. Однако производительность системы при определенных видах операций может пострадать. Например, увеличение емкости может потребовать выделения большего массива, копирования первого массива во второй и последующего выполнения операций. Это может быть довольно медленно по сравнению, например, с та же операция над связанным списком. Таким образом, имеет смысл выбрать, чтобы емкость ArrayList была больше или, по крайней мере, сопоставима с фактическим количеством элементов, ожидаемых в реальной среде выполнения.

7
James Hart

Если вы создаете новый массив myArray = new Object[100], то вы можете читать и писать от myArray[0] до myArray[99] (и вы обнаружите, что он полон null).

Если вы создаете ArrayListmyList = new ArrayList(100), тогда вы пытаетесь get или set любые элементы, вы получите IndexOutOfBoundsException, потому что List пуст, пока вы не add что-то для него.

Таким образом, массив размера 100 первоначально будет содержать 100 nulls, но List будет пустым.

2
khelwood

Это просто кажется плохо сформулированным и потенциально неправильным, если я не правильно понимаю.

Я полагаю, что он пытается сказать, что существует разница между начальной емкостью ArrayList и начальным размером ArrayList.

List<Employee> employees = new ArrayList<>(100);
int size = employes.size();

размер будет 0, в то время как начальная емкость равна 100.

Вы правы в том, как вы читаете исходный код.

2
Reid Harrison

Разница между контейнером fixed size (структура данных) и контейнером variable size.

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

List - это контейнер variable size, число элементов в котором может изменяться в диапазоне от 0 до любого количества, которое вы хотите (с учетом ограничений реализации). После создания количество элементов может увеличиваться или уменьшаться. Вы всегда можете получить любой элемент по его индексу.

Но концепция Java List на самом деле является интерфейсом и может быть реализована многими различными способами. Таким образом, ArrayList, LinkedList и т.д. За списком существует структура данных, которая фактически содержит элементы. И сама эта структура данных может иметь фиксированный размер или переменный размер, и в любой момент времени может иметь точный размер числа элементов в списке или может иметь некоторое extra «буферное» пространство.

Например, LinkedList в своей структуре данных всегда имеет точно такое же количество «мест для элементов», как и в списке, который он представляет. Но ArrayList использует массив фиксированной длины в качестве резервного хранилища.

Для ArrayList в любой момент времени число элементов в списке может отличаться от количества элементов, которое может содержать массив за ним. Эти «дополнительные» места для элементов просто содержат нули или 0 или что-то еще, но ArrayList никогда не дает вам доступ к этим местам. Когда вы добавляете элементы в переменную ArrayList, они занимают больше места в базовом массиве, пока, наконец, базовый массив не заполнится. Элемент next, который вы добавляете в ArrayList, вызывает выделение совершенно нового массива фиксированного размера - несколько большего размера, чем «текущий» массив, и все элементы списка, скопированные в него (исходный массив отбрасывается). Чтобы предотвратить слишком частое выполнение этой дорогостоящей операции (выделение и копирование), новый массив больше текущего массива (по некоторому фактору) и, таким образом, содержит элементы, которые в то время не будут содержать элементы списка - они пусты (нулевые) или 0).

Таким образом, поскольку существует (потенциально) разница между количеством представляемых элементов в списке и количеством элементов, которое может содержать реализуемая структура данных, действуют two концепции.

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

(Кстати, для контейнеров фиксированного размера size часто называют length , поэтому массивы имеют свойство length, а строки имеют метод length () . Разные языки - иногда даже один и тот же язык - используйте «размер» и «длину» непоследовательно, но они всегда означают размер , а термин «емкость» всегда используется для размера/длины базовой структуры данных.)

1
davidbak

Давайте использовать пример из реальной жизни. Рассмотрим восемнадцатиместный автобус, вместимость которого составляет восемнадцать пассажиров. Размер пассажиров в любой момент времени может быть не более восемнадцати, но не более. Когда количество пассажиров восемнадцать, другой пассажир не может быть размещен.

В ArrayList емкость имеет что-то общее с нашей шиной в том смысле, что она определяет количество элементов, которые могут поместиться. Однако, в отличие от нашей шины, емкость расширяется, чтобы вместить количество элементов до Integer.MAX_VALUE.

То же самое касается размера, так же как и нашей шины, размер элементов в списке не может превышать емкость. Представьте себе, когда 50 пассажиров едут на восемнадцатиместном автобусе! Ты точно не хочешь быть в этом автобусе.

0
X09