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 []) ) является более конкретным.

  1. Вторая фаза (§15.12.2.3) выполняет разрешение перегрузки при разрешении бокса и распаковки, но все же исключает использование вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до третьей фазы.

Это гарантирует, что метод никогда не выбирается посредством вызова метода переменной arity, если он применим посредством вызова метода фиксированной arity.

  1. Третий этап (§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, поэтому выходит за пределы массива