2012-07-25 94 views
0

我正在學習java中的任務,並且遇到了一個錯誤,我無法找到答案。 不知何故,當我對由iterator.next()返回的對象調用gethit()方法時,出現堆棧溢出異常。 我懷疑因爲gethit()方法(在這個特定情況下)遞歸調用自己。儘管如此,我認爲堆棧溢出很奇怪,因爲遞歸深度只有2或3層,而我的對象不會使用過多的內存。Java堆棧溢出,因爲遞歸方法調用

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

「遞歸只能達到2或3級」 - 你確定嗎? – 2012-07-25 20:31:23

回答

1

每次你打電話迭代,將調用另一個迭代器,調用另一個迭代器,等等。因此,從無限遞歸由於每個迭代一次又一次地呼籲

iterator.next().gethit(); 

每個迭代器只是使需要通過一個新的迭代器,但你繼續調用getHit(),所以你永遠不會完成你的堆棧溢出任何函數調用。

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

  • 無論何時調用方法,它會將信息推送到堆棧幀,在方法完成時,堆棧幀將被刪除。你的情況是沒有辦法的方法完成和去除堆棧幀,它產生的StackOverflowError

0

儘管實現遞歸你應該確保有一個終呼其中,該方法不調用自身。

現在你認爲這個遞歸應該停止,因爲你正在移動到鄰居並檢查它們是否被擊中但是當你看到呼叫時... (這是幹運行的初始位置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() + "]"); 
    .... 
} 

這裏的解決辦法是保持小區的名單,把它作爲參數,這是訪問,並從來沒有拜訪過他們再次。希望這可以幫助。