ArrayList.remove 在调用为 Collection.remove 时给出不同的结果

2022-09-02 03:08:04

此代码:

    Collection<String> col = new ArrayList<String>();    
    col.add("a");
    col.add("b");
    col.add("c");
    for(String s: col){       
       if(s.equals("b"))
             col.remove(1);  
       System.out.print(s);  

    } 

指纹:abc

同时这个:

    ArrayList<String> col = new ArrayList<String>();    
    col.add("a");
    col.add("b");
    col.add("c");
    for(String s: col){       
       if(s.equals("b"))
             col.remove(1);  
       System.out.print(s);  

    } 

指纹:ab

但是,它应该打印相同的结果...怎么了?


答案 1

Collection只有方法,如果找到,它将删除传递的对象。boolean remove(Object o)

ArrayList也具有 ,它可以通过其索引删除元素。public E remove(int index)

您的第一个代码段调用 ,它不会删除任何内容,因为您不包含 .您的第二个代码段调用并删除索引为 1 的元素(即删除 )。boolean remove(Object o)ArrayList1public E remove(int index)"b"

不同的行为源于这样一个事实,即方法重载解析发生在编译时,并且取决于要为其调用该方法的变量的编译时类型。当类型为 时,只考虑接口的方法(以及该接口继承的方法)进行重载解析。colCollectionremoveCollection

如果替换为 ,则两个代码段的行为将相同。col.remove(1)col.remove("b")

正如Tamoghna Chowdhury所评论的那样,可以接受一个原始的论点 - 在你的情况下 - 由于自动装箱到一个实例。对于第二个代码段,选择的原因是方法重载解析过程首先尝试查找匹配的方法而不执行自动装箱/取消装箱转换,因此它只考虑 。boolean remove(Object o)intintIntegerpublic E remove(int index)boolean remove(Object o)public E remove(int index)


答案 2

要在迭代它时安全地删除它,您应该使用 .CollectionIterator

ArrayList<String> col = new ArrayList<String>();    
col.add("a");
col.add("b");
col.add("c");

Iterator<String> i = col.iterator();
while (i.hasNext()) {
   String s = i.next(); // must be called before you can call remove
   if(s.equals("b"))
      i.remove();
   System.out.print(s);
}

关于,从集合中删除在工作时对您不起作用的原因是由于以下原因:ArrayList

  1. 该方法将删除此列表中指定位置处的元素。将任何后续元素向左移动(从其索引中减去一个元素)。因此,这个对你有用。java.util.ArrayList.remove(int index)

  2. 该方法从此集合中删除指定元素的单个实例(如果存在)(它是可选操作)。更正式地说,删除一个元素,如果此集合包含一个或多个这样的元素。如果此集合包含指定的元素(或者等效地,如果此集合由于调用而更改,则返回此集合)。java.util.Collection.remove(Object o)e(o==null ? e==null : o.equals(e))true

希望,这有帮助。