簡體   English   中英

ArrayList.remove(int)與ArrayList.remove(Object)在不同的線程中

[英]ArrayList.remove(int) vs ArrayList.remove(Object) in different thread

我有一個Minion對象的ArrayList,當盾牌與一個Minion發生碰撞時,我想從ArrayList中刪除該Minion。 但是,我只能使它以一種方式工作,而不能以另一種方式工作。 誰能解釋為什么?

在所有3種情況下,我都使用Android的Renderer的onDrawFrame()方法...因此我無法控制何時調用它。 但是這是所有三種方式的代碼:

方法1:(不起作用)

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));” 被稱為二十億次。

方法2:(仍然無法正常工作)

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被調用了太多次,並且在錯誤的時間訪問了arraylist,我需要鎖定它。但是它仍然無法正常工作。再次,該行minions.remove(indexesToRemove.get(i));使用正確的索引正確調用,但實際上minions.remove(indexesToRemove.get(i));刪除該對象。我正在看着屏幕上的盾牌猛擊到小爪子上,但什么也沒發生奴才(不會從arraylist中刪除)

方法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);行中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> ,因此該調用綁定到第二個簽名,在該簽名中,您可以通過直接指定對象來刪除元素,因此自動拆箱不會將您的Integer轉換為int以便找不到該元素並且什么也沒有發生。

嘗試使用: minions.remove((int)indexesToRemove.get(i))以便正確應用方法的靜態綁定。

@傑克的答案是正確的。 為了后代,您應該在此處使用Iterator ,可以循環Iterator其刪除:

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

在第一個兩個示例中,它將Integer視為對象ref,並將其轉換為int

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM