扫雷程序中的NullPointerException

时间:2012-02-08 21:32:18

标签: java class inheritance nullpointerexception

所以,我是一名计算机科学专业的学生,​​也是一名刚刚掌握Java的程序员。有人让我帮他们完成一项任务,他们必须创建一个非常基本的扫雷程序。该计划根本不使用标记地雷,但除此之外,它在功能上与任何其他扫雷游戏相同。

当我尝试运行程序时,我遇到了NullPointerException。我已经研究了这可能意味着什么,现在知道这应该是NoObjectException或DereferenceException,但我仍然没有更接近解决问题。

调用Tile类的makeField方法时会出现此异常。另外,我真的试图围绕正确的继承,静态与非静态,公共与私有,以及所有这些相互关联,所以如果这是一个完全的noob问题,我很抱歉。 / p>

所以,我有一个主文件,一个Tile超类,以及tile类的两个子类--Bomb和Flat。炸弹是一个带有炸弹的瓷砖,而Flat是任何不是炸弹的瓷砖。

public class MineSweeperMain{
public static void main(String[] args)
{
    Scanner kybd = new Scanner(System.in);
    int dimension;
    Tile[][] gameBoard;

    System.out.print("Enter the dimension of the board you would like to play on:\t");
    dimension = kybd.nextInt();

    gameBoard = Tile.makeField(dimension);
    Tile.printField(gameBoard, dimension);
}

}

//

public class Tile {

static Random rand = new Random();

boolean isBomb;
boolean isRevealed;
int posX, posY;
int noOfAdjacentMines;

public Tile()
{
    isRevealed = false;
}

public static int detectMines(Tile[][] board, int dimensions)
{
    int detectedMines = 0;
    for(int i = 0; i < dimensions; i++)
    {
        for(int j = 0; j < dimensions; j++)
        {
            if(board[i][j].isBomb)
                detectedMines++;
        }
    }
    return detectedMines;
}

public static Tile[][] makeField(int dimensions)
{   
    int rowOfMines = dimensions / 3;
    int randomInRow;

    Tile[][] Board = new Tile[dimensions][dimensions];

    for(int i = 0; i < dimensions; i++)
        for(int j = 0; j <= rowOfMines; j++)
        {
        randomInRow = rand.nextInt(dimensions);
        Board[i][randomInRow] = new Bomb();
        }

    for(int i = 0; i < dimensions; i++)
        for(int j = 0; j < dimensions; j++)
        {
            if(!Board[i][j].isBomb)
                Board[i][j] = new Flat();
        }
    return Board;               
}

public static void printField(Tile[][] board, int dimensions)
{
    for(int i = 0; i <= dimensions; i++)
    {
        for (int j = 0; j <= dimensions; j++)
        {
            if(i ==0)
                System.out.print(i + " ");
            else if(j == 0)
                System.out.print(j + " ");
            else
            {
                if(board[i-1][j-1].isRevealed && !board[i-1][j-1].isBomb)
                    System.out.print(board[i-1][j-1].noOfAdjacentMines + " ");  
                else
                    System.out.print("# ");
            }
        }
    }
}

}

//

public class Flat extends Tile{

public Flat()
{
    noOfAdjacentMines = 0;
    isBomb = false;
    isRevealed = false;
}
}

//

public class Bomb extends Tile{
public Bomb()
{
    isBomb = true;
    isRevealed = false;
}

}

//

6 个答案:

答案 0 :(得分:6)

您的问题出现在我认为的makeField方法的第二个循环中。

检查if(!Board[i][j].isBomb)时,由于尚未完全填充数组,因此该特定值将为null。第一个循环放置了几个随机炸弹,但其余值都为空。

我建议你扭转你的循环。首先循环遍历所有内容,然后在不检查任何内容的情况下将整个板放在Flat之外。

然后在第二个循环中,您只需用Flat s覆盖一对Bomb

另一个解决方案是进行这个微小的修改并检查null:

if(null == Board[i][j] || !Board[i][j].isBomb)

请注意,如果采用此解决方案,则空检查必须为 FIRST 。这是因为名为short-circuting的东西。

我推荐我的第一个解决方案虽然切换循环是因为它消除了1个额外的比较,而不是大笔交易,但你永远不知道...

答案 1 :(得分:5)

那里有很多问题,但要回答为什么你得到一个空指针的主要问题:

Board[i][randomInRow] = new Bomb();

在上面的代码中,您将在每行的电路板周围随机放置炸弹。请注意,这只会将值设置为方块的子集。

然后你遍历每个方格并执行以下操作:

if(!Board[i][j].isBomb) Board[i][j] = new Flat();

问题是,如果广场没有被分配为炸弹,它没有被分配任何东西,所以它是空的。当你在null的东西上调用isBomb时,你会得到一个空指针。此测试应该是检查Board[i][j] == null

话虽如此,你可能想要从小开始。虽然就游戏而言是相对基础的,但我认为在深入了解之前你需要更多对java的基本理解。

答案 2 :(得分:5)

我想我看到了问题。制作电路板时,您可以将炸弹设置为连续的随机元素。然后你检查所有这些,看看那里是否有炸弹。

if(!Board[i][j].isBomb) // What if board[i][j] is not set? Null Pointer Exception
                Board[i][j] = new Flat();

这有用吗?

答案 3 :(得分:0)

问题是您没有填写Bomb数组。

你需要这样的东西:

    for(int i = 0; i < dimensions; i++)
        for(int j = 0; j < dimensions; j++){
            Board[i][j] = new Tile(); // or something
            if(!Board[i][j].isBomb()) // use an accessor
            Board[i][j] = new Flat();
        }
    return Board;               
}

答案 4 :(得分:0)

这里的问题是未使用默认磁贴初始化电路板。

你有:

Tile[][] Board = new Tile[dimensions][dimensions];

然后你随机分配炸弹:

Board[i][randomInRow] = new Bomb();

不是炸弹的瓷砖仍然是空的。所以调用它会导致NPE(NullPointerException):

if (!Board[i][j].isBomb)

要解决此更改,请执行以下操作:

if (!Board[i][j] == null)

所以,如果那个当前位置的棋盘是空的,那么肯定它没有被初始化为炸弹 还有其他方法可以转动和扭曲代码来解决这个问题,但这是我想到的最简单的方法。

答案 5 :(得分:-1)

声明多维数组时,不会在数组中创建任何对象。你需要像

这样的东西
for(int i = 0; i < dimensions; i++) {
    for(int j = 0; j < dimensions; j++) {
        Board[i][j] = new Tile();
    }
}