加州大学伯克利分校 CS61B:数据结构(免费在线课程)- 项目 0:2048 游戏问题 - METHOD IS GIVING ME NULL POINTER EXCEPTION ERROR

UC Berkley CS61B: Data Structures (Free online course) - Project 0: 2048 Game question - METHOD IS GIVING ME NULL POINTER EXCEPTION ERROR

我很难为项目 0 实施以下方法:2048 游戏:

public static boolean maxTileExists(Board b)

如果棋盘中的任何牌等于获胜牌值 2048,则此方法应 return 为真。请注意,不要将常量 2​​048 硬编码到您的代码中,您应该使用 MAX_PIECE,它是模型 class 的一部分的常量。换句话说,你不应该做 if (x == 2048) 而应该做 if (x == MAX_PIECE)。 留下像 2048 这样的硬编码数字是一种糟糕的编程习惯,有时被称为“幻数”。这种神奇数字的危险在于,如果您在代码的一部分而不是另一部分更改它们,您可能会得到意想不到的结果。通过使用像 MAX_PIECE 这样的变量,您可以确保它们全部一起更改。 编写方法后,TestMaxTileExists.java 中的测试应该会通过。

下面是我的代码:

 /**
     * Returns true if any tile is equal to the maximum valid value.
     * Maximum valid value is given by MAX_PIECE. Note that
     * given a Tile object t, we get its value with t.value().
     */
    public static boolean maxTileExists(Board b) {
        // TODO: Fill in this function.
        for (int i = 0; i < b.size(); i++) {
            for (int j = 0; j < b.size(); j++) {
                if (b.tile(i, j).value() == MAX_PIECE) {
                    return true;
                }
            }
        }
        return false;
    }

我在测试时一直收到这个错误:

java.lang.NullPointerException:无法调用“game2048.Tile.value()”,因为“game2048.Board.tile(int, int)”的 return 值为空

我需要实现的第一个方法如下,它运行良好并通过了所有测试用例:

public static boolean emptySpaceExists(Board b)

如果给定棋盘中的任何图块为空,则此方法应该 return 为真。您不应以任何方式为此项目修改 Board.java 文件。对于此方法,您需要使用 Board class 的 tile(int col, int row) 和 size() 方法。不需要其他方法。 注意:我们在设计 Board class 时使用了一个特殊的关键字 private,它不允许您直接使用 Board 的实例变量。例如,如果您尝试访问 b.values[0][0],这将不起作用。这是一件好事!它迫使您学习使用 tile 方法,您将在项目的其余部分使用它。 尝试打开 TestEmptySpace.java 文件夹。 运行 测试。您应该看到 6 个测试失败,其中 2 个通过。正确编写 emptySpaceExists 方法后,TestEmptySpace 中的所有 8 个测试都应该通过。

下面是代码:

/**
     * Returns true if at least one space on the Board is empty.
     * Empty spaces are stored as null.
     */
    public static boolean emptySpaceExists(Board b) {
        // TODO: Fill in this function.
        for (int i = 0; i < b.size(); i++) {
            for (int j = 0; j < b.size(); j++) {
                if (b.tile(i, j) == null) {
                    return true;
                }
            }
        }
        return false;
    }

首先,当您尝试访问尚未初始化的内容时,通常会发生 NullPointerException。在您的情况下,这是 .value() 函数。

在您的第二个代码块中,您可能会意识到您使用的代码有一个主要区别:这将是代码的“== null”部分,而不是“.value() == MAX_PIECE".

现在,为什么其中一个会抛出错误而另一个不会?

这是因为当您检查某物是否为“空”时,您会看到它是否存在。如果不存在,那么您的程序将 return 为真,如果它确实存在,那么您的程序将 return 为假。

另一方面,当您在对象上调用 .value() 时,您已经假定该对象存在。这意味着,例如,如果对象尚未初始化,您的程序将尝试取消引用存储在变量中的指针,但很快就会意识到该指针实际上并未指向任何东西。

要修复此类错误,您只需确保您尝试访问的内容存在。

举个例子:假设我们有 人 x.

Person x;

在这里我们可以很快看到,如果我们尝试这样的事情,我们会抛出一个错误:

System.out.println(x.name());

当然是因为x还不存在

然而,如果我们想知道 Person x 是否存在,我们只需这样做:

System.out.println(x == null);

在我们的例子中,这并不是真正必要的,因为我们可以清楚地看到 Person x 尚未定义,但在像你这样的例子中,你同时处理许多不同的对象,像这样的一行可以真的帮了我们。

这意味着,如果你想确保你不会在你的方法中抛出 NullPointerException,你只需添加一行(或更改一行,这是防止异常的更简洁的版本学习的目标)。

public static boolean maxTileExists(Board b) {
    // TODO: Fill in this function.
    for (int i = 0; i < b.size(); i++) {
        for (int j = 0; j < b.size(); j++) {
            if (b.tile(i, j) == null) continue;
            if (b.tile(i, j).value() == MAX_PIECE) {
                return true;
            }
        }
    }
    return false;
}

通过添加继续 for 循环的 if 语句,我们跳过了程序试图取消引用似乎不存在的对象的那一点。

但是,在使用此代码之前需要注意一件重要的事情: 也有可能您的 should 已经存在,我认为这很有可能。这将是您的代码中的一个更深层次的问题,您可以通过遍历并确保在程序开始时初始化每个图块来解决这个问题。