Java ArrayList删除对象 – IndexOutOfBoundsException

我试图从ArrayList中删除一个对象,但我不断收到IndexOutOfBounds错误。 现在有很多信息可用,为什么在删除迭代 ArrayList 会发生这种情况,但是我不这样做。 例:

ArrayList a = new ArrayList(); 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.(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) 

为什么会这样?

编辑澄清这个问题不是这个问题的重复:

这里发生的具体问题与迭代时删除元素时的常见问题无关。 它更多是由重载的ArrayList remove方法和java自动从char转换为int的。

另一个问题的答案中没有涉及这方面。

有两个重载的remove方法 – 一个将int作为索引 , 另一个采用Object ,以删除对象引用本身。

JLS的第15.12.2节介绍了Java如何选择一种方法重载而不是另一种方法。

阶段是:

  1. 第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换 ,或使用变量arity方法调用。 如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

这保证了在Java SE 5.0之前在Java编程语言中有效的任何调用都不会因为引入变量arity方法,隐式装箱和/或取消装箱而被认为是不明确的。 但是,变量arity方法(第8.4.1节)的声明可以更改为给定方法方法调用表达式选择的方法,因为变量arity方法在第一阶段被视为固定arity方法。 例如,在已经声明m(Object)的类中声明m(Object …)会导致不再为某些调用表达式(例如m(null))选择m(Object),因为m(Object [] )更具体。

  1. 第二阶段(第15.12.2.3节)执行重载解析, 同时允许装箱和拆箱 ,但仍然排除使用变量arity方法调用。 如果在此阶段没有找到适用的方法,则处理继续到第三阶段。

这确保了如果通过固定的arity方法调用适用,则永远不会通过变量arity方法调用来选择方法。

  1. 第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合。

(大胆强调我的)

这两种方法都适用,因为char可以提升为int ,但也可以装入一个Character ,匹配a ‘s type参数。 但是Java会在任何需要装箱的方法之前单独选择促销,因此'A'被提升为int ,因此值为65。

如果要通过对象引用删除,可以将其显式转换为Character

 a.remove((Character) 'A'); 

remove方法需要一个索引,它会删除指定索引处的项。 您正在传递一个char,因此它将转换为整数65。

ArrayList类有两个重载方法remove 。 一个带有整数参数,用于删除该索引处的项目,另一个带有Object参数。

你传了一个char 。 这既不是int也不是Object 。 因此编译器必须决定它使用哪个remove :它是否将char提升为int ,还是将其装入一个Character ,然后将其提升为Object

Java中的重载决策始终在不考虑装箱和拆箱的情况下启动。 因此它优先考虑remove(int)重载。 因此它需要字符A的值,即65,并将其提升为int,这意味着当列表只有三个项目时,它将尝试删除项目#65。

要解决此问题,您需要明确告诉它使用Character对象,如: remove(Character.valueOf('A'))

应该将索引传递给Arraylist的remove方法。 试图替换这条线a.remove(’A’); 同

a.remove(0);

 a.remove() 

期望获取要删除的项的索引的整数。 ‘A’返回A的ASCII值,即64,因此超出了数组的范围