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

标签 java android multithreading list arraylist

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

在所有 3 种情况下,我都在使用 Android 渲染器的 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));”被调用 bijillion 次。

方法二:(还是不行)

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 的另一个实例变量副本外,是否有更好的方法来管理 ArrayList<Minion> colliders = new ArrayList<Minion>(minions);

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

最佳答案

因为 ArrayList提供两种方法:

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

当您调用 minions.remove(indexesToRemove.get(i)) 时, 自 indexesToRemoveList<Integer> ,调用绑定(bind)到第二个签名,您可以通过直接指定对象来删除元素,自动拆箱不会打开您的 Integer进入 int因此未找到该元素并且没有任何反应。

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

关于java - ArrayList.remove(int) 与不同线程中的 ArrayList.remove(Object),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14467464/

相关文章:

c - 带栅栏的 SPSC 线程安全

c - 如何理解多线程和互斥原语

java - 多线程场景下的数据可见性

java - 时间格式始终来自特定时区

java - block 所有者窗口 Java FX

java - 在java中实现没有数据库的不同类型的连接

php - 如何设置CMS作为Android应用程序的后端?

Java 8 Stream - 如何返回用要查找的项目列表替换字符串内容

java - 您如何检查 Realm 实例是否已经关闭?

android - 即使可见性设置为消失,FloatingActionButton 仍可见一段时间