简体   繁体   English

Java ArrayList删除对象 - IndexOutOfBoundsException

[英]Java ArrayList remove object - IndexOutOfBoundsException

I am trying to remove an object from an ArrayList, but I keep getting an IndexOutOfBounds Error. 我试图从ArrayList中删除一个对象,但我不断收到IndexOutOfBounds错误。 Now there is plenty information available why this happens when iterating over the ArrayList while removing , however I'm not doing that. 现在有很多信息可用,为什么在删除迭代 ArrayList 会发生这种情况,但是我没有这样做。 Example: 例:

 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);

prints [A, B, C] and then fails with: 打印[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)

Why is this happening? 为什么会这样?

EDIT to clarify this question is not a duplicate of this question : 编辑澄清这个问题不是一个重复这个问题

The specific problem that is occuring here has nothing to do with the usual problems when removing elements while iterating. 这里发生的具体问题与迭代时删除元素时的常见问题无关。 It is rather caused by the overloaded ArrayList remove method and the automatic type conversion from char to int by java. 它更多是由重载的ArrayList remove方法和java自动从char转换为int的。

This aspect is not covered in the answer of the other question. 另一个问题的答案中没有涉及这方面。

There are 2 overloaded remove methods -- one that takes an int as an index , and one that takes an Object , to remove the object reference itself. 有两个重载的remove方法 - 一个将int作为索引另一个采用Object ,以删除对象引用本身。

Section 15.12.2 of the JLS covers how Java chooses one method overload over another. JLS的第15.12.2节介绍了Java如何选择一种方法重载而不是另一种方法。

The phases are: 阶段是:

  1. The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion , or the use of variable arity method invocation. 第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换 ,或使用变量arity方法调用。 If no applicable method is found during this phase then processing continues to the second phase. 如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. 这保证了在Java SE 5.0之前在Java编程语言中有效的任何调用都不会因为引入变量arity方法,隐式装箱和/或取消装箱而被认为是不明确的。 However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. 但是,变量arity方法(第8.4.1节)的声明可以更改为给定方法方法调用表达式选择的方法,因为变量arity方法在第一阶段被视为固定arity方法。 For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null)), as m(Object[]) is more specific. 例如,在已声明m(Object)的类中声明m(Object ...)会导致不再为某些调用表达式(例如m(null))选择m(Object),因为m(Object [] )更具体。

  1. The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing , but still precludes the use of variable arity method invocation. 第二阶段(§15.12.2.3)执行重载解析, 同时允许装箱和拆箱 ,但仍然排除使用变量arity方法调用。 If no applicable method is found during this phase then processing continues to the third phase. 如果在此阶段没有找到适用的方法,则处理继续到第三阶段。

This ensures that a method is never chosen through variable arity method invocation if it is applicable through fixed arity method invocation. 这确保了如果通过固定的arity方法调用适用,则永远不会通过变量arity方法调用来选择方法。

  1. The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing. 第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合。

(bold emphasis mine) (大胆强调我的)

Both methods are applicable here, because a char can be promoted to an int , but it can also be boxed to a Character , matching a 's type parameter. 这两种方法都适用,因为char可以提升为int ,但也可以装入一个Character ,匹配a类型参数。 But Java will choose promotion alone before any method that requires boxing, so 'A' is promoted to int , hence the value 65. 但是Java会在任何需要装箱的方法之前单独选择促销,因此'A'被提升为int ,因此值为65。

You can cast it explicitly to Character if you want to remove by object reference. 如果要通过对象引用删除,可以将其显式转换为Character

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

The remove method expects an index and it removes an item at the specified index. remove方法需要一个索引,它会删除指定索引处的项。 You are passing a char, thus it is converted to an integer 65. 您正在传递一个char,因此它将转换为整数65。

The ArrayList class has two overloads of the method remove . ArrayList类有两个方法remove重载。 One with an integer parameter, that removes the item at that index, and one with an Object parameter. 一个带有整数参数,用于删除该索引处的项目,另一个带有Object参数。

You are passing a char . 你传了一个char This is neither an int not an Object . 这既不是int也不是Object So the compiler has to decide which remove it uses: Does it promote the char to an int , or does it box it into a Character which will then be promoted to Object . 所以编译器必须决定它使用哪个remove :它是否将char提升为int ,或者将它装入一个Character ,然后将其提升为Object

Overload resolution in Java always starts without consideration of boxing and unboxing. Java中的重载分辨率始终在不考虑装箱和拆箱的情况下启动。 Therefore it gives priority to the remove(int) overload. 因此它优先考虑remove(int)重载。 So it takes the value of the character A , which is 65, and promotes it to int, which means it will try to remove item #65, when the list only has three items. 因此它需要字符A的值,即65,并将其提升为int,这意味着当列表只有三个项目时,它将尝试删除项目#65。

To solve this, you need to explicitly tell it to use a Character object, as in: remove(Character.valueOf('A')) . 要解决此问题,您需要明确告诉它使用Character对象,如: remove(Character.valueOf('A'))

Should pass index to the remove method of Arraylist. 应该将索引传递给Arraylist的remove方法。 trying replacing this line a.remove('A'); 试图替换这条线a.remove('A'); with

a.remove(0); a.remove(0);

a.remove()

expects to get an integer for the index of the item to be removed. 期望获取要删除的项的索引的整数。 'A' returns the ASCII value of A which is 64,thus out of the bounds of the array 'A'返回A的ASCII值,即64,因此超出了数组的范围

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM