我正在研究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();
}
答案 0 :(得分:1)
每次调用迭代器时,都会调用另一个将调用另一个迭代器的迭代器,依此类推。因此,由于每个迭代器调用
,您的堆栈会因无限递归而溢出iterator.next().gethit();
每个迭代器只会创建一个需要经过的新迭代器,但是你会一次又一次地调用getHit(),所以你永远不会完成任何函数调用。
答案 1 :(得分:1)
iterator.next()getHit();调用getHit()方法并再次启动迭代并继续(递归循环)。有一个变量或终止点来退出递归循环。
每当调用方法时,它都会将信息推送到堆栈帧,方法完成堆栈帧将被删除。在您的情况下,无法完成方法并删除堆栈帧,这会生成StackOverFlowError
答案 2 :(得分: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() + "]");
....
}
这里的解决方案是保留一个单元格列表,将其作为参数传递,这些参数将被访问,并且永远不会再访问它们。希望这会有所帮助。