Java ArrayList <двойная> проблема IndexOutOfBoundsException

У меня есть проблема с ArrayList. Мне нужен он для хранения результата. Поскольку я хочу запуститься с элемента n, я пытался дать ArrayList способность с ensureCapacity(n+1) использовать set(n,x) но я добираюсь IndexOutOfBoundsException.

Я пытался сохранить n add(x) перед использованием набора и это работает.

Таким образом, я хотел бы знать, почему это не работает над моим путем и как решить это потому что помещенные n времена a add(x) не хороший стиль ;-)

5
задан Bozho 18 May 2010 в 05:16
поделиться

7 ответов

Если вам не нравится использовать собственный цикл и метод list add напрямую, то есть другой способ. Создайте свой ArrayList с нужным количеством элементов, например:

final int MAX_ELEMENTS = 1000;
List<Integer> myList = new ArrayList<Integer>(
    Collections.<Integer>nCopies(MAX_ELEMENTS, null));

Или, если у вас уже есть список, размер которого вы хотите увеличить на n элементов:

myList.addAll(Collections.<Integer>nCopies(n, null));

(Обратите внимание, здесь я предполагал, что список будет содержать объекты Integer , но вы можете изменить его на свой собственный тип. Если вы работаете с типами raw / pre-Java 5, просто отбросьте общий декларации.)

Что касается вашего фактического вопроса: емкость! = содержимое. ArrayList внутренне имеет как физический массив, так и счетчик того, что на самом деле находится в нем. При увеличении емкости внутренний массив изменяется таким образом, что он может содержать такое количество элементов, однако счетчик не изменяется. Вам нужно добавить элементы, чтобы увеличить это количество.

С другой стороны, если вы просто пытаетесь установить определенные элементы и знаете максимум, который вы хотите использовать, почему бы не использовать массив напрямую? Если затем вам нужно передать этот массив в API, который принимает List s, используйте Arrays.asList . Другие классы по-прежнему могут изменять содержимое вашего резервного массива, но они не смогут увеличить его размер или емкость.

6
ответ дан 18 December 2019 в 11:54
поделиться

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

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

7
ответ дан 18 December 2019 в 11:54
поделиться

Вы получаете это исключение, потому что sureCapacity () только проверяет, достаточно ли выделенной памяти для добавления объектов в ArrayList, я Поверьте, это на тот случай, если вы хотите добавить сразу несколько объектов без необходимости перемещать память.

Чтобы сделать то, что вы хотите, вам нужно сначала запустить ArrayList с нулевыми элементами ...

int n = 10;  //capacity required
ArrayList foo = new ArrayList();

for( int i=0; i<=n; i++ ) {
      foo.add(null);
}

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

0
ответ дан 18 December 2019 в 11:54
поделиться

sureCapacity () имеет другое назначение. Его следует использовать в случаях, когда вы узнаете требуемый размер Списка после его создания. Если вы знаете размер до того, как он станет конструктором, просто передайте его в качестве аргумента конструктору.

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

  • , размер поддерживающего массива увеличивается
  • , поле size в ArrayList нет.

Это, однако, нормально, поскольку емкость! = Размер

Используйте метод add (..) , который является единственным методом увеличения размера . поле:

ArrayList list = new ArrayList();
list.ensureCapacity(5); // this can be done with constructing new ArrayList(5)

for (int i = 0; i < list.size - 1; i ++) {
   list.add(null);
}
list.add(yourObject);
0
ответ дан 18 December 2019 в 11:54
поделиться

Возможно, вам стоит переосмыслить выбор использования List . Возможно, что Map будет более подходящим, если элементы должны быть добавлены в нечетном порядке.

Уместно ли это, зависит от знаний о вашем использовании, которых у меня пока нет.

Будет ли структура данных в конечном итоге заполнена полностью или данные будут скудными?

0
ответ дан 18 December 2019 в 11:54
поделиться

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

Из книги Брюса Экеля «Мышление на Java» :

В личном сообщении Джошуа Блох написал: «... Я считаю, что мы ошиблись, разрешив детали реализации (такие как размер хеш-таблицы и коэффициент загрузки) в наши API. Клиент должен , возможно, сообщить нам максимальный ожидаемый размер коллекции, и мы должны взять его оттуда. Клиенты могут легко принести больше вреда, чем пользы, выбрав значения для этих параметров. В качестве крайнего примера рассмотрим capacityIncrement. Никто никогда не должен устанавливать это, и мы не должны были предоставлять его. Если вы установите любое ненулевое значение, асимптотическая стоимость последовательности добавлений переходит от линейной к квадратичной. Другими словами, она снижает вашу производительность. Со временем мы начинаем подумайте об этом . Если вы посмотрите на IdentityHashMap, вы увидите, что он не имеет параметров настройки нижнего уровня »

2
ответ дан 18 December 2019 в 11:54
поделиться

то, что другие люди говорили о ensureCapacity() ...

вы должны написать класс типа DynamicArrayList extends ArrayList. затем просто переопределить add(n,x), чтобы сделать с логикой for loop add(null), о которой говорилось.

0
ответ дан 18 December 2019 в 11:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: