2012-02-08 35 views
4

所以我是一名计算机科学专业的学生,​​也是一名Java初学程序员。有人要求我帮助他们完成一项任务,他们必须创建一个非常基本的扫雷计划。这个程序根本不使用标志性矿山,但除此之外,它在功能上与其他扫雷机游戏相同。扫雷程序中的NullPointerException

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

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

所以,我有一个主文件,一个Tile超类,以及两个子类 - 炸弹和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; 
} 

} 

//

+1

哪里是NullPointerException? (哪个语句?) – RussS 2012-02-08 21:36:35

+5

读取异常的堆栈跟踪。这不是毫无意义的垃圾。它告诉你在代码中异常发生的位置,以及抛出异常时整个调用堆栈是什么。如果您不理解它,请将其发布到您的问题中,然后告诉我们它指向哪一行代码。 – 2012-02-08 21:37:10

+1

1)类应以大写字母开头,变量名称以小写字母开头。 2)'System.out.println'对于一个简单的NullPointerException来说是一个方便的调试工具,只是为了查看什么引用实际上是空的,并从那里开始工作。 – rtheunissen 2012-02-08 21:38:24

回答

6

你的问题是我认为makeField方法的第二个循环。

当您检查if(!Board[i][j].isBomb)该特定值将为空,因为您尚未完全填充阵列。第一个循环放置了一些随机炸弹,但其余的值为空。

我会建议逆转你的循环。首先循环播放所有内容,并且不用检查任何东西就可以从Flats中取出整个板。

然后在你的第二个循环,你只是简单地覆盖一对夫妇Flat s的Bomb小号

另一种解决方案是只是为了让这个小小的修改,检查空:

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

注如果你采取这种解决方案,空检查必须是FIRST。这是因为所谓的short-circuting

我建议切换回路虽然我的第一个解决方案的原因是因为它消除了1间额外的比较,而不是大问题,但你永远不知道...

+0

啊,非常感谢。我现在知道了。我会用你的第一个建议。 – Gthoma2 2012-02-08 21:54:03

5

有一个LO的问题,也吨,但回答为什么你得到一个空指针的主要问题:

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

在上面的代码,你放置炸弹随机各地板每排。请注意,这只会为正方形的一个子集设置一个值。

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

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

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

这就是说,你可能想要开始比这更小。虽然对于游戏来说相对比较基础,但我认为在深入研究这类事情之前,您需要对java有更多的基本了解。

5

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

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

这个功能有用吗?

+0

是的,非常感谢。 – Gthoma2 2012-02-08 21:54:25

-1

当你宣布你的多维度数组你不获取您的数组中创建的任何对象。你需要像

for(int i = 0; i < dimensions; i++) { 
    for(int j = 0; j < dimensions; j++) { 
     Board[i][j] = new Tile(); 
    } 
} 
+0

@JamesMontagne你是对的,没有看到数组是用两个维数声明的。当然,你可以按照我写的方式创建数组,也就是说你将如何为每个子数组创建一个长度不同的多维数组(例如创建一个三角形数组)。 – 2012-02-08 21:54:06

+0

是的,我收回第二部分。此外,只是供参考,而不是我的downvote。 – 2012-02-08 21:57:27

+0

@JamesMontagne嗯,你有一个有效的评论。谢谢。 – 2012-02-08 22:02:05

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

这就是问题所在,但这个解决方案会覆盖他刚刚放置的所有炸弹。 – 2012-02-08 21:47:35

0

这里的问题是,该板未使用默认的瓷砖初始化。

您有:

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

,然后你随机分配炸弹:

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

那不是炸弹仍空的瓷砖。所以调用,这将导致NPE(空指针异常):

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

为了解决这个改变该行:

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

所以,如果董事会在该当前位置是空无疑,这是未初始化作为一个炸弹。
还有其他方法可以转换和扭曲代码来解决这个问题,但这是我想到的最简单的方法。