簡體   English   中英

ArrayList僅在arraylist中的對象上的索引超出范圍異常

[英]ArrayList Index out of bounds exception on only object in the arraylist

我知道這個問題以前可能已經被問過很多遍了,但是我有一個問題,我找不到特別針對我的問題的解決方案。

問題如下:

我有兩個火箭和彈丸的數組列表,並檢查了它們之間的碰撞。 當它們碰撞時,它們都將被移除。 問題是,當擊中arraylist中唯一的火箭時,就會發生異常,而我不知道如何阻止它的發生。

java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at adam.miszczak.defendthebase.level.Level.collision(Level.java:158)
at adam.miszczak.defendthebase.level.Level.tick(Level.java:144)
at adam.miszczak.defendthebase.Game.tick(Game.java:124)
at adam.miszczak.defendthebase.Game.run(Game.java:104)
at java.lang.Thread.run(Unknown Source)

碰撞方法+數組列表:

public static ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
private static ArrayList<Rocket> rockets = new ArrayList<Rocket>();

private void collision(){
    for(int i = 0; i < rockets.size(); i++){
        for(int j = 0; j < projectiles.size(); j++){
            try{
                if(rockets.get(i).bounds().intersects(projectiles.get(j).bounds())){
                    projectiles.remove(j);
                    rockets.get(i).die();
                    stats.addScore(rockets.get(i));
                    Particle p = new Particle(20, 20, 20, 50);
                    particles.add(p);
                }
            }catch(IndexOutOfBoundsException e){
                e.printStackTrace();
            }
        }
    }
}

刪除和添加方法:

private void remove(ArrayList<Projectile> projectiles, ArrayList<Rocket> rockets){
    for(int i = 0; i < rockets.size(); i++){
        if(rockets.get(i).getVisible()){ rockets.remove(i); rocketsOnScreen--; }
    }

    for(int i = 0; i < projectiles.size(); i++){
        if(projectiles.get(i).isRemoved()){ projectiles.remove(i);}
    }

    for(int i = 0; i < planes.size(); i++){
        if(planes.get(i).isRemoved()){ planes.remove(i); planesOnLevel--;}
    }
}

private void spawnRocket(int rocketType, int x, ArrayList<Rocket> rockets) {
    switch (rocketType) {
        case ROCKET_NORMAL:
            rockets.add(new NormalRocket(x, -10, 80, 0, 2));
            rocketsSpawned++;
            rocketsOnScreen++;
            break;
        case ROCKET_FIRE:
            if(difficulty > 1 && random.nextInt(100) > fireRocketSpawn){
                    rockets.add(new FireRocket(x, -10, 70, 0, 2));
                    rocketsSpawned++;
                    rocketsOnScreen++;
            }else{
                return;
            }
            break;
        case ROCKET_ZIPPER:
            if(difficulty > 2 && random.nextInt(100) > zipperRocketSpawn){
                rockets.add(new ZipperRocket(x, -10, 40, 0, 4));
                rocketsSpawned++;
                rocketsOnScreen++;
            }else{
                return;
            }
            break;
        case ROCKET_TANK:
            if(difficulty > 3 && random.nextInt(100) > tankRocketSpawn){
                rockets.add(new TankRocket(x, -10, 130, 0, 1));
                rocketsSpawned++;
                rocketsOnScreen++;
            }else{
                return;
            }
            break;
    }
} 

注意:rocket.die()基本上只是刪除火箭,就像remove方法一樣。

使用Iterator以外的其他任何方法遍歷List無法刪除。 想象一下后果。 您正在遍歷元素並刪除元素n 所有其他元素向下移動一個以填補空白。 您取元素n+1 ,現在是開始循環時的元素n+2 而且List縮小了一個元素,因此您的邊界檢查現在是錯誤的。 您可以通過這種方式獲得各種難以跟蹤的錯誤。

在Java中,如果使用正確的語法(即增強的foreach循環),則即使您在迭代時甚至嘗試從列表中添加/刪除列表,也將獲得正確的錯誤-您將獲得ConcurrentModificationException

要修正您的方法,請執行以下操作:1)刪除所有索引。 您正在濫用它們,它們是不必要的(現在很多時候,您在每次迭代中是否從每個List中獲得相同的元素?)。 2)對內部循環使用實際的Iterator ,以便可以調用Iterator.removeList刪除最后一個返回的元素。 因為這是通過Iterator完成的,所以不會導致錯誤:

private void collision() {
    for (final Rocket rocket : rockets) {
        final Iterator<Projectile> iter = projectiles.iterator();
        while (iter.hasNext()) {
            final Projectile projectile = iter.next();
            if (rocket.bounds().intersects(projectile.bounds())) {
                rocket.die();
                stats.addScore(rocket);
                Particle p = new Particle(20, 20, 20, 50);
                particles.add(p);
                iter.remove();
            }
        }
    }
}

切勿在列表循環中刪除列表中的項目。 它可能會帶來並發障礙。 在循環之后立即標記要刪除的數字。

不知道它是否可以解決您的問題,但您肯定也應該解決該問題。

當檢測到碰撞時,您致電

rockets.get(i).die();

您說,“ die”將火箭從“ Arraylist”中移除。 然后你打電話

stats.addScore(rockets.get(i));

這將崩潰(此行是158,不是嗎?)

為簡潔和格式而道歉,我的手機首先回答了:-)

暫無
暫無

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

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