0

我想创建一个坐标类,当我实例化这个类时,它会自动构建它的6个相邻坐标,但是,当我这样做时,我总是遇到stackoverflow问题,我没有很好的方法来解决它。这是我的错误代码,您可以很容易地看到问题,构造函数本身包含自己。所以我想知道如何解决这个问题

public class Coordinate {

    private final int x;
    private final int y;
    private final Coordinate[] periperal;

    /**
     * The default constructor for Coordinate class that
     * sets up the coordinate to the given integers.
     * 
     * @param x value of x coordinate
     * @param y value of y coordinate
     */

    public Coordinate(){
        final Coordinate adjacent1 = new Coordinate(x, y + 1);
        final Coordinate adjacent2 = new Coordinate(x, y - 1);
            final Coordinate adjacent3 = new Coordinate(x - 1, y + 1);
        final Coordinate adjacent4 = new Coordinate(x - 1, y);
        final Coordinate adjacent5 = new Coordinate(x + 1, y);
        final Coordinate adjacent6 = new Coordinate(x + 1, y - 1);
        Coordinate[] list = {adjacent1, adjacent1, adjacent1, adjacent1, adjacent1, adjacent1};
        periperal = list;
    } 

我知道为什么我错了,但我不知道如何解决它。有人可以帮我吗?非常感谢。

4

5 回答 5

2

构造函数中的第一行递归且无条件地创建另一个实例。实际上,这是一个调用自身的方法。

你需要一些条件来阻止这种递归永远进行(或者更确切地说,直到你用完堆栈)。

为整个(无限)坐标系中的每个坐标创建一个实例将不起作用。你确定你需要邻居坐标吗?我猜,如果/如果真的需要它们,它们可以在稍后即时计算。

于 2013-01-23T07:45:45.250 回答
1

@Thilo 解释了您的代码有什么问题(+1)。我想建议你一个解决方案。您实际上想要创建Coordinate包含 6 个其他实例的Coordinate. 您不能从同一个构造函数调用构造函数:它会产生无限递归。

所以这里是解决方案:

  1. 创建接受假参数的私有构造函数(只是为了区分它和“真实”构造函数)。从“真实”构造函数中调用它。这将防止无限递归。
  2. 使构造函数包受到保护。从构造函数中删除调用构造函数的代码。创建创建所有实例并将辅助实例设置为主实例的工厂(或工厂方法)。
于 2013-01-23T07:51:46.490 回答
0

与其在构造函​​数中设置相邻坐标,不如将其移到一个名为 newInstance() 的静态方法中,并使构造函数私有:

public class Coordinate {

    private final int x;
    private final int y;
    private Coordinate[] periperal;

    /**
     * The default constructor for Coordinate class that
     * sets up the coordinate to the given integers.
     * 
     * @param x value of x coordinate
     * @param y value of y coordinate
     */

    public static Coordinate newInstance(int x, int y){
        final Coordinate instance = new Coordinate(x, y);
        final Coordinate adjacent1 = new Coordinate(x, y + 1);
        final Coordinate adjacent2 = new Coordinate(x, y - 1);
        final Coordinate adjacent3 = new Coordinate(x - 1, y + 1);
        final Coordinate adjacent4 = new Coordinate(x - 1, y);
        final Coordinate adjacent5 = new Coordinate(x + 1, y);
        final Coordinate adjacent6 = new Coordinate(x + 1, y - 1);
        Coordinate[] list = {adjacent1, adjacent2, adjacent3, adjacent4, adjacent5, adjacent6};
        instance.setPeriperal(list);
        return instance;
    }

    private Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }

    private void setPeriperal(Coordinate[] periperal) {
        this.periperal = periperal;
    }
} 
于 2013-01-23T07:58:39.670 回答
0

你做错事了。正如其他人所说,您正在覆盖无限区域,不仅如此,您还无限次地创建每个坐标 (x,y) 创建 (x,y+1) 并且相对于自身创建 (x,y-1) 即第一个。

为了防止这些问题,您需要限制区域(创建坐标时,您需要minX,maxX,minY,maxY并测试坐标是否在外面,在这种情况下不要创建它)。为了防止递归创建相同的坐标,您需要存储已经创建的某个位置,当您需要坐标时,查看那里,如果找不到,创建并记住它。这样每个坐标只会被创建一次。

更好的方法是首先为整个板创建坐标并将它们存储在数组中(其中(x,y)被转换为 x*width+y,因此您可以使用一维数组。它们添加连接。

但即使这样也没有必要。您可以在需要时使用实际坐标并计算邻居。这样,您将用更多的计算来换取大量未使用的内存(并且 java 存储小对象的效率低下,这对许多长寿命的小对象造成了伤害,并且检索它们可能比重新计算成本更高)。但无论如何,过早优化是万恶之源。所以首先让它工作,只有当它太慢时,让它更快。

另一种情况是,如果您需要无限可能(但在每个实际情况下都受实际使用的限制)板。在这种情况下,您需要一些懒惰的方法并避免存储您不需要的东西。

于 2013-01-23T08:11:23.120 回答
0

替代解决方案:不要在构造函数中创建相邻的 Coordinate 对象。在创建第一个点的任何地方创建它们,然后使用 setter 方法设置相邻坐标。

于 2013-01-23T08:56:21.770 回答