【问题标题】:ArrayList.remove(int) vs ArrayList.remove(Object) in different threadArrayList.remove(int) vs ArrayList.remove(Object) 在不同的线程
【发布时间】:2013-01-06 05:01:14
【问题描述】:

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

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

方法一:(不起作用)

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?
    }
}

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

方法二:(还是不行)

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?
        }
    }
}

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

方法#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?
        }
    }
}

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

谁能解释一下?

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

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

【问题讨论】:

    标签: java android multithreading list arraylist


    【解决方案1】:

    因为ArrayList提供了两种方法:

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

    当您调用minions.remove(indexesToRemove.get(i)) 时,由于indexesToRemoveList&lt;Integer&gt;,因此调用绑定到您通过直接指定对象删除元素的第二个签名,自动拆箱不会打开您的@987654326 @ 转换为 int,因此找不到该元素并且没有任何反应。

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

    【讨论】:

    • 废话。好眼力。难怪。谢谢你的收获,解释得很好。
    【解决方案2】:

    @Jack 的回答是正确的。对于后代,您应该在此处使用Iterator,您可以使用 inside 将其删除:

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

    【讨论】:

    • 其他人解释了原因。但我喜欢你修得最好的。我完全忘记了迭代器。谢谢!!
    【解决方案3】:

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

    【讨论】:

    • 不用投,直接打电话Integer.intValue()
    猜你喜欢
    • 2018-02-17
    • 2023-03-02
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 2013-11-27
    • 2021-03-13
    相关资源
    最近更新 更多