[英]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))
,由於indexesToRemove
是List<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.