java ArrayList.remove(int) 与不同线程中的 ArrayList.remove(Object)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14467464/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 16:23:47  来源:igfitidea点击:

ArrayList.remove(int) vs ArrayList.remove(Object) in different thread

javaandroidmultithreadinglistarraylist

提问by David T.

I have an ArrayList of Minion objects, and when a shield collides with a minion, I want to remove that minion from the ArrayList. However, I can only get it to work in 1 way, but not the other way. can anyone plz explain why?

我有一个 Minion 对象的 ArrayList,当盾牌与 Minion 碰撞时,我想从 ArrayList 中删除该 Minion。但是,我只能让它以一种方式工作,而不能以另一种方式工作。谁能解释一下为什么?

In all 3 cases, I'm using Android's Renderer's onDrawFrame() method... so I have no control over when it gets called. but here's the code for all 3 ways:

在所有 3 种情况下,我都使用 Android 的 Renderer 的 onDrawFrame() 方法......所以我无法控制它何时被调用。但这是所有 3 种方式的代码:

Method 1: (does not work)

方法一:(不起作用)

public void onDrawFrame(GL10 gl) {
    List<Integer> indexesToRemove = new ArrayList<Integer>();
    int len = minions.size();
    for(int i=0; i<len; i++){
        if( OverlapTester.overlapCircleRectangle( (Circle)shield1.bounds,  (Rectangle)minions.get(i).bounds) ){ //this tests out to work just fine
            indexesToRemove.add(i);
        }
    }
    for(int i=indexesToRemove.size()-1; i>=0; i--){
        minions.remove(indexesToRemove.get(i)); //<------ why doesn't this work?
    }
}

the problem is that that last line minions.remove(indexesToRemove.get(i));doesn't ACTUALLY remove the minions. it DOES get called, with the proper index. i've stepped through the debugger, ran it straight up, and the arraylist isn't modified at all. why is this? actually, in the debugger, that line "minions.remove(indexesToRemove.get(i));" gets called a bijillion times.

问题是最后一行minions.remove(indexesToRemove.get(i));实际上并没有删除仆从。它确实被调用,并带有正确的索引。我已经通过调试器,直接运行它,并且根本没有修改数组列表。为什么是这样?实际上,在调试器中,该行“minions.remove(indexesToRemove.get(i));” 被称为 bijillion 次。

Method 2: (still does not work)

方法二:(还是不行)

public void onDrawFrame(GL10 gl) {
    synchronized(minions){
        List<Integer> indexesToRemove = new ArrayList<Integer>();
        int len = minions.size();
        for(int i=0; i<len; i++){
            if( OverlapTester.overlapCircleRectangle( (Circle)shield1.bounds,  (Rectangle)minions.get(i).bounds) ){ //this tests out to work just fine
                indexesToRemove.add(i);
            }
        }
        for(int i=indexesToRemove.size()-1; i>=0; i--){
            minions.remove(indexesToRemove.get(i)); //<------ why doesn't this work?
        }
    }
}

In here, I thought... "oh maybe since it's not quite synchronized, the drawFrame sometimes gets called too many times and is accessing the arraylist at the wrong time and i need to lock it. but it still doesn't work. again, that line minions.remove(indexesToRemove.get(i));gets called properly with the right index, but does NOT actually remove the object. i'm watching my shield on the screen slam right into the minion and nothing happens to the minion (it doesn't get removed from the arraylist)

在这里,我想......“哦,也许因为它不是很同步,所以有时 drawFrame 被调用了太多次并且在错误的时间访问了数组列表,我需要锁定它。但它仍然不起作用。再次, 该行minions.remove(indexesToRemove.get(i));被正确的索引正确调用,但实际上并没有删除对象。我正在看着屏幕上的盾牌直接撞到小兵,小兵没有任何反应(它没有从数组列表中删除)

Method #3 (this actually works)

方法#3(这确实有效)

public void onDrawFrame(GL10 gl) {
    ArrayList<Minion> colliders = new ArrayList<Minion>(minions);
    int len = colliders.size();
    for(int i=0; i<len; i++){
        GameObject collider = colliders.get(i);
        if(OverlapTester.overlapCircleRectangle((Circle)shield1.bounds, (Rectangle)collider.bounds)){
            minions.remove(collider); // <---- why does THIS work instead?
        }
    }
}

this code works perfectly. the shield smacks the minion and the minion drops dead. as you can see here, the ONLY difference is that i'm using the overloaded ArrayList.remove(object)method instead of removing by index. as in the line minions.remove(collider);. why does THIS work ?

这段代码完美无缺。盾牌击中仆从,仆从倒地死亡。正如您在此处看到的,唯一的区别是我使用的是重载ArrayList.remove(object)方法而不是按索引删除。就像在行中一样minions.remove(collider);。为什么这有效?

can anyone please explain?

谁能解释一下?

on a side note, aside from storing another instance variable copy of the arraylist, is there a better way to manage ArrayList<Minion> colliders = new ArrayList<Minion>(minions);?

附带说明一下,除了存储数组列表的另一个实例变量副本之外,还有更好的管理方法ArrayList<Minion> colliders = new ArrayList<Minion>(minions);吗?

Note: both Shield and Minion are regular Java objects that have a rectangular shape as boundary. all that math checks out just fine. i've tested it in the debugger and the collision detection is accurate. I'm also updating the bounds/positions accurate in the onDrawFrame()method.

注意:Shield 和 Minion 都是以矩形为边界的常规 Java 对象。所有的数学检查都很好。我已经在调试器中对其进行了测试,碰撞检测是准确的。我也在更新onDrawFrame()方法中准确的边界/位置。

回答by Hyman

Because ArrayListprovides two methods that are:

因为ArrayList提供了两种方法,它们是:

public E remove(int index)
public boolean remove(Object o)

When you invoke minions.remove(indexesToRemove.get(i)), since indexesToRemoveis a List<Integer>, the invocation is bound to the second signature in which you remove an element by directly specifying the object, auto-unboxing doesn't turn your Integerinto an intso the element is not found and nothing happens.

当您调用minions.remove(indexesToRemove.get(i)),因为indexesToRemove是 a List<Integer>,调用绑定到您通过直接指定对象删除元素的第二个签名,自动拆箱不会将您Integer变成 an ,int因此找不到该元素并且没有任何反应。

Try with: minions.remove((int)indexesToRemove.get(i))so that static binding of the method is correctly applied.

尝试使用:minions.remove((int)indexesToRemove.get(i))以便正确应用该方法的静态绑定。

回答by Gray

@Hyman's answer is correct. For posterity you should be using an Iteratorhere that you can remove with insideyour loop:

@Hyman 的回答是正确的。对于后代,您应该使用Iterator可以循环删除的此处:

// synchronization wrapper here
Iterator<Minion> iterator = minions.iterator();
while (iterator.hasNext()) {
    Minion minion = iterator.next();
    if( OverlapTester.overlapCircleRectangle(..., minion.bounds)) {
        iterator.remove();
    }
}

回答by Ryan

It's treating Integer as an object ref in the 1st two example, cast it to an int

它在第一个两个示例中将 Integer 视为对象 ref,将其转换为 int