0

私はJavaで学校の課題に取り組んでいますが、答えが見つからないエラーに遭遇しました。gethit()どういうわけか、返されたオブジェクトでメソッドを呼び出すとiterator.next()、スタック オーバーフロー例外が発生します。gethit()メソッド(この特定のケースでは)が再帰的にそれ自体を呼び出すためだと思います。とはいえ、再帰が 2 レベルまたは 3 レベルの深さしかなく、オブジェクトが過剰な量のメモリを使用しないため、スタック オーバーフローが発生するのは奇妙だと思います。

shoot()最初の呼び出しを行うメソッドgethit()

public void shoot() {
    assert canHaveAsEnergy(energy - 1000);

    //Search the target position.
    Position laserPos = new Position(getPos().getX(), getPos().getY(), getPos().getBoard());
    do {
        long nextX = laserPos.getX() + new Double(orientation.getDirection().getX()).longValue();
        long nextY = laserPos.getY() + new Double(orientation.getDirection().getY()).longValue();
        laserPos.setX(nextX);
        laserPos.setY(nextY);
    } while (getPos().getBoard().canHaveAsPosition(laserPos) && (! getPos().getBoard().hasAsPosition(laserPos)));
    //Hit every entity on the target position. 
    for (Entity entity : getPos().getBoard().getAllEntitiesOn(laserPos)) {
        entity.getHit();
    }
    setEnergy(energy - 1000);
}

getHit()自分自身を再帰的に呼び出すメソッド。

public void getHit() {
    ArrayList<Position> neighbours = new ArrayList<Position>();
    Position northPos = new Position(getPos().getX(), getPos().getY() - 1, getPos().getBoard());
    Position eastPos = new Position(getPos().getX() + 1, getPos().getY(), getPos().getBoard());
    Position southPos = new Position(getPos().getX(), getPos().getY() + 1, getPos().getBoard());
    Position westPos = new Position(getPos().getX() - 1, getPos().getY(), getPos().getBoard());
    neighbours.add(northPos);
    neighbours.add(eastPos);
    neighbours.add(southPos);
    neighbours.add(westPos);

    for (Position pos : neighbours) {
        if (getPos().getBoard().hasAsPosition(pos)) {
            Iterator<Entity> iterator = getPos().getBoard().getAllEntitiesOn(pos).iterator();
            while (iterator.hasNext()) {
                //Somehow this gives a stack overflow error
                iterator.next().getHit();
            }
        }       
    }
    System.out.println(this.toString() + " takes a hit and explodes.");
    getPos().getBoard().removeAsEntity(this);
    terminate();
}
4

3 に答える 3

1
  • iterator.next().getHit(); getHit() メソッドを呼び出すと、反復が再び開始され、継続します (再帰ループ)。再帰ループを終了するための変数または終点を用意します。

  • メソッドが呼び出されるたびにスタック フレームに情報がプッシュされ、メソッドの完了時にスタック フレームが削除されます。あなたの場合、StackOverFlowErrorを生成するメソッドの完了とスタックフレームの削除の方法はありません

于 2012-07-25T20:29:57.847 に答える
1

イテレーターを呼び出すたびに、別のイテレーターを呼び出す別のイテレーターが呼び出されます。したがって、すべてのイテレータ呼び出しによる無限再帰からのスタックオーバーフロー

iterator.next().gethit();

各反復子は通過する必要がある新しい反復子を作成するだけですが、getHit() を何度も呼び出し続けるため、関数呼び出しを完了することはありません。

于 2012-07-25T20:29:40.670 に答える
0

再帰を実装するときは、メソッドがそれ自体を呼び出さない終了呼び出しが 1 つあることを確認する必要があります。

ここで、隣人に移動し、それらがヒットしたかどうかを確認しているときに、この再帰が停止する必要があると仮定しますが、呼び出しが表示されると... (これは、初期位置 2,2 でドライランしたものです)

[Original]=>[P1],[P2],[P3],[P4]
**[2,2]**=>[2,1],[3,2],[2,3],[1,2]
[2,1]=>[2,0],[3,1],**[2,2]**,[1,1]
[3,2]=>[3,1],[4,2],[3,3],[2,2]
[2,3]=>[2,2],[3,3],[2,4],[1,3]
[1,2]=>[1,1],[2,2],[1,3],[0,2]

したがって、ここで最初に 4 つの近隣を計算getHit()し、それを呼び出します。ソース セルは、いずれかの隣接セルの隣接セルになります。これは、無限再帰に入るのに十分です。

次のステートメントを入れることで、あなたの価値観を特定できます...

public void getHit() {
    System.out.println("[" + getPos().getX() + "," + getPos().getY() + "]");
    ....
}

ここでの解決策は、セルのリストを保持し、それをパラメーターとして渡します。これらのセルは訪問され、二度と訪問されることはありません。お役に立てれば。

于 2012-07-26T07:56:09.060 に答える