Java ArrayList удалить объект - IndexOutOfBoundsException
Я пытаюсь удалить объект из ArrayList, но я продолжаю получать IndexOutOfBounds Error. Теперь доступно много информации, почему это происходит, когда итерация поверх ArrayList при удалении, однако я этого не делаю.
Пример:
ArrayList<Character> a = new ArrayList<Character>();
a.add('A');
a.add('B');
a.add('C');
System.out.println(a);
a.remove('A');
System.out.println(a);
печатает [A, B, C]
, а затем сбой:
java.lang.IndexOutOfBoundsException: Index: 65, Size: 3
at java.util.ArrayList.rangeCheck(ArrayList.java:635)
at java.util.ArrayList.remove(ArrayList.java:474)
at b.<init>(b.java:23)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at bluej.runtime.ExecServer$3.run(ExecServer.java:746)
Почему это происходит?
EDIT, чтобы прояснить этот вопрос, не является дубликатом этого вопроса:
Конкретная проблема, которая здесь возникает, не имеет ничего общего с обычными проблемами при удалении элементов при повторении. Это скорее вызвано перегруженным методом ArrayList remove
и автоматическим преобразованием типов от char
до int
с помощью java.
Этот вопрос не рассматривается в ответе на другой вопрос.
Ответы
Ответ 1
Есть 2 перегруженных метода remove
- тот, который принимает int
как индекс, и один который принимает Object
, чтобы удалить ссылку на объект.
В разделе 15.12.2 JLS описывается, как Java выбирает один метод для перегрузки над другим.
Фазы:
- Первая фаза (§15.12.2.2) выполняет разрешение перегрузки без разрешения преобразования бокса или распаковки или использования вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до второй фазы.
Это гарантирует, что любые вызовы, которые были действительны на языке программирования Java до Java SE 5.0, не считаются двусмысленными в результате внедрения методов переменной arity, неявного бокса и/или распаковки. Однако объявление метода переменной arity (§8.4.1) может изменить метод, выбранный для выражения вызова метода данного метода, поскольку метод переменной arity рассматривается как метод фиксированной arity в первой фазе. Например, объявление m (Object...) в классе, который уже объявляет m (Object), приводит к тому, что m (Object) больше не выбирается для некоторых выражений вызова (таких как m (null)), как m (Object []) ) является более конкретным.
- Вторая фаза (§15.12.2.3) выполняет разрешение перегрузки при разрешении бокса и распаковки, но все же исключает использование вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до третьей фазы.
Это гарантирует, что метод никогда не выбирается посредством вызова метода переменной arity, если он применим посредством вызова метода фиксированной arity.
- Третий этап (§15.12.2.4) позволяет комбинировать перегрузку с использованием методов переменной arity, бокса и распаковки.
(смелый акцент мой)
Оба метода применимы здесь, потому что a char
можно повысить до int
, но его также можно добавить в класс Character
, соответствующий параметру типа a
. Но Java будет выбирать продвижение самостоятельно перед любым методом, который требует бокса, поэтому 'A'
продвигается до int
, следовательно, значение 65.
Вы можете явно указать его на Character
, если хотите удалить ссылку на объект.
a.remove((Character) 'A');
Ответ 2
Метод remove
ожидает индекс и удаляет элемент по указанному индексу. Вы передаете char, поэтому преобразуется в целое число 65.
Ответ 3
Класс ArrayList
имеет две перегрузки метода remove
. Один с целочисленным параметром, который удаляет элемент в этом индексе и один с параметром Object
.
Вы передаете char
. Это не int
не Object
. Поэтому компилятор должен решить, какой remove
он использует: продвигает ли он char
на int
, или он помещает его в Character
, который затем будет продвигаться до Object
.
Разрешение перегрузки в Java всегда начинается без учета бокса и распаковки. Поэтому он отдает приоритет перегрузке remove(int)
. Таким образом, он принимает значение символа A
, которое равно 65, и продвигает его к int, что означает, что он попытается удалить элемент # 65, когда список содержит только три элемента.
Чтобы решить эту проблему, вам нужно явно указать ей, чтобы использовать объект Character
, как в: remove(Character.valueOf('A'))
.
Ответ 4
Должен передать индекс методу удаления Arraylist. попытка заменить эту строку
a.remove( 'А'); с
a.remove(0);
Ответ 5
a.remove()
ожидает получить целое число для индекса элемента, который нужно удалить. "A" возвращает значение ASCII для A, которое равно 64, поэтому выходит за пределы массива