簡體   English   中英

由於遞歸方法調用,Java堆棧溢出

[英]Java stack overflow because of recursive method call

我正在研究java中的學校作業,我遇到了一個錯誤,我無法找到答案。 不知何故,當我調用gethit()方法通過返回的對象上iterator.next()我得到堆棧溢出異常。 我懷疑因為gethit()方法(在這種特定情況下)以遞歸方式調用自身。 盡管如此,我認為獲得堆棧溢出是很奇怪的,因為遞歸只有2或3級深度,並且我的對象不會使用過多的內存。

第一次調用gethit()shoot()方法

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();
}

每次調用iterator時,都會調用另一個將調用另一個迭代器的迭代器,依此類推。 因此,由於每個迭代器調用,您的堆棧都會因無限遞歸而溢出

iterator.next().gethit();

每個迭代器只會創建一個需要經過的新迭代器,但是你會一次又一次地調用getHit(),所以你永遠不會完成任何函數調用。

  • iterator.next()getHit(); 調用getHit()方法並再次啟動迭代並繼續(遞歸循環)。 有一個變量或終止點來退出遞歸循環。

  • 每當調用方法時,它都會將信息推送到堆棧幀,在方法完成時,堆棧幀將被刪除。 在您的情況下,無法完成方法並刪除堆棧幀,這會生成StackOverFlowError

在實現Recursion時,您應該確保有一個終止調用,其中方法不會調用自身。

現在你假設這個遞歸應該停止,因為你正在移動到鄰居並檢查它們是否被擊中但是當你看到呼叫時......(這是初始位置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()時。 Source單元格是任何一個鄰居的鄰居,這足以進入無休止的遞歸。

您可以通過輸入以下聲明來識別您的值...

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

這里的解決方案是保留一個單元格列表,將其作為參數傳遞,這些參數將被訪問,並且永遠不會再訪問它們。 希望這可以幫助。

暫無
暫無

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

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