从不同类调用方法时出现 NullPointer 异常
JAVA- 你好, 我正在编写一个扫雷程序(第一个大人物),但我真的陷入困境。根据我要遵循的规范,程序本身由 2 个类组成(一个用于逻辑,一个用于 GUI)。我在两门课上都做了相当多的事情,但也还没有完成。然而,我正在尝试测试从一个类到另一个类的调用方法的实现,这就是我陷入困境的地方。在 GUI 类中,每次用户单击某个框时,我都会尝试调用逻辑类中的 openCell(int x, int y) 方法。该逻辑类方法将依次检查方块上是否有地雷、0 或数字,并从 GUI 类调用适当的方法。错误涉及的两个方法如下:
GUI CLASS
public void mouseClicked(MouseEvent e) {
for (int x = 0 ; x < width ; x++) {
for (int y = 0 ; y < height ; y++) {
if (e.getSource() == table[x][y]) {
if(e.getButton() == e.BUTTON1) {
MinesweeperLogic logicClass = new MinesweeperLogic();
logicClass.isOpen(x, y); // <--------------------------- ERROR
}}}}}
LOGIC CLASS
boolean openCell(int x, int y) {
isClicked[x][y] = true;
if(mine[x][y] == true && flag[x][y]==false) {
return false;
} else if(neighborBombs(x, y) > 0 && flag[x][y]==false) {
return true;
}else {
marked = true;
return marked;
}}
以下是用户点击游戏中的某个框后收到的错误报告(编译代码时确实捕获了它):
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at MinesweeperLogic.isOpen(MinesweeperLogic.java:117)
at MineSweeperGUI.mouseClicked(MineSweeperGUI.java:126)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:253)
at java.awt.Component.processMouseEvent(Component.java:6266)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3255)
at java.awt.Component.processEvent(Component.java:6028)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4247)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
at java.awt.Container.dispatchEventImpl(Container.java:2085)
at java.awt.Window.dispatchEventImpl(Window.java:2475)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
最后,整个(虽然此时不完整) )到目前为止,如果需要的话,可以编写两个类的代码。 (逻辑类中的方法需要根据项目的说明执行特定操作,并且逻辑类中不得有用户交互)。我无法弄清楚到底是什么导致了错误。任何指导将不胜感激。 (希望这不是很明显的事情,因为尽管我得了流感,但我在过去的几个小时里一直在试图弄清楚这一点!哈哈)。
import java.awt.* ;
import java.awt.event.* ;
import java.awt.geom.* ;
import javax.swing.* ;
import javax.swing.event.* ;
public class MineSweeperGUI extends JFrame implements ActionListener, MouseListener {
int width = 10;
int height = 10;
JPanel p = new JPanel();
JButton[][] table = new JButton[width][height];
public void MineSweeper() {
MinesweeperLogic logicClass = new MinesweeperLogic();
logicClass.startNewGame(width, height);
JButton[] button = new JButton[width*height];
GridLayout layout = new GridLayout (width, height) ;
p.setLayout(layout);
for(int x = 0 ; x < width ; x++) {
for(int y = 0 ; y < height ; y++) {
table[x][y] = new JButton();
table[x][y].setPreferredSize(new Dimension(25,25));
table[x][y].addMouseListener (this);
p.add(table [x] [y]);
}
}
this.add(p);
this.pack();
this.setVisible(true);
}
public void mouseClicked(MouseEvent e) {
for (int x = 0 ; x < width ; x++) {
for (int y = 0 ; y < height ; y++) {
if (e.getSource() == table[x][y]) {
if(e.getButton() == e.BUTTON1) {
MinesweeperLogic logicClass = new MinesweeperLogic();
logicClass.isOpen(x, y); //<--------------------------------------
}
}
}
}
}
public void gameover(int x, int y) {
table[x][y].setText("*");
}
public static void main(String[]args) {
MineSweeperGUI guiClass = new MineSweeperGUI();
guiClass.MineSweeper();
}}
public void actionPerformed(ActionEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public class MinesweeperLogic {
private int w, h, maxBombs, bombsremaining;
public int width, height;
private boolean mine[][];
private boolean flag[][];
private boolean isClicked[][];
private boolean isZero[][];
private boolean marked;
public void startNewGame(int width, int height) {
w = width;
h = height;
flag = new boolean[w][h];
isZero = new boolean[w][h];
isClicked = new boolean[w][h];
mine = new boolean[w][h];
maxBombs =(int) Math.floor (width*height*0.15);
bombsremaining = maxBombs;
for(int i = 0; i < maxBombs; i++) {
int x = (int) (Math.random() * (w));
int y = (int) (Math.random() * (h));
if (mine[x][y] == false) {
mine[x][y] = true;
isClicked[x][y] = false;
flag[x][y] = false;
}
}
}
int getWidth() {
return w;
}
int getHeight() {
return h;
}
boolean openCell(int x, int y) { // <---------------------------------------------
//MineSweeperGUI guiClass = new MineSweeperGUI();
isClicked[x][y] = true;
if(mine[x][y] == true && flag[x][y]==false) {
//guiClass.gameover(x, y);
return false;
} else if(neighborBombs(x, y) > 0 && flag[x][y]==false) {
return true;
} else {
marked = true;
return marked;
}}
boolean markCell(int x, int y) {
if(flag[x][y] == true) {
flag[x][y] = false;
isClicked[x][y] = false;
bombsremaining++;
marked = false;
return marked;
} else {
flag[x][y] = true;
isClicked[x][y] = true;
bombsremaining--;
if(mine[x][y]==true) {
return true;
} else {
return false;
}
}
}
boolean isOpen(int x, int y) {
if(isClicked[x][y] == false) {
return false;
} else {
return true;
}
}
boolean isMarked(int x, int y) {
if(flag[x][y] == true) {
return true;
} else {
return false;
}
}
int getValue(int x, int y) {
if(mine[x][y] == true) {
return -1;
} else {
return neighborBombs(x, y);
}
}
private int neighborBombs(int x, int y) { // checks surrounding 8 squares for number of bombs
int surBombs = 0;
for (int q = x - 1 ; q <= x + 1 ; q++) {
for (int w = y - 1 ; w <= y + 1 ; w++) {
while (true) {
if (q < 0 || w < 0 || q >= w || w >= h) {
break;
}
if (mine[q][w] == true) {
surBombs++;
break;
}
}
}
}
return surBombs;
}
}
JAVA-
Hi,
I am writing a minesweeper program (first biggie) and am really stuck. The program itself is comprised of 2 classes (one for the logic, one for the GUI) as per the specifications that I am to follow. I have done a fair bit in both classes but am not finished either. However, I am attempting to test implementing call methods from one class to the other and that is where I get stuck. From the GUI class, I am attempting to call the method openCell(int x, int y) in the Logic Class every time the user clicks on a box. That Logic Class method will in turn check to see whether there is a mine, a 0 or a number on the square and call the appropriate method from the GUI class. The two methods involved in the error are as follows:
GUI CLASS
public void mouseClicked(MouseEvent e) {
for (int x = 0 ; x < width ; x++) {
for (int y = 0 ; y < height ; y++) {
if (e.getSource() == table[x][y]) {
if(e.getButton() == e.BUTTON1) {
MinesweeperLogic logicClass = new MinesweeperLogic();
logicClass.isOpen(x, y); // <--------------------------- ERROR
}}}}}
LOGIC CLASS
boolean openCell(int x, int y) {
isClicked[x][y] = true;
if(mine[x][y] == true && flag[x][y]==false) {
return false;
} else if(neighborBombs(x, y) > 0 && flag[x][y]==false) {
return true;
}else {
marked = true;
return marked;
}}
Following is the error report I recieve once the user clicks on a box in the game (it does to catch it when compiling the code):
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at MinesweeperLogic.isOpen(MinesweeperLogic.java:117)
at MineSweeperGUI.mouseClicked(MineSweeperGUI.java:126)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:253)
at java.awt.Component.processMouseEvent(Component.java:6266)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3255)
at java.awt.Component.processEvent(Component.java:6028)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4247)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
at java.awt.Container.dispatchEventImpl(Container.java:2085)
at java.awt.Window.dispatchEventImpl(Window.java:2475)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Finally, the entire (tho incomplete at this point) code for two classes so far if needed. (The methods in the logic class are required to perform specific actions as per the instructions of the project and must have no user interaction in the logic class). I cannot figure out what exactly is causing the error. Any guidance would be greatly appreciated. (hopefully it's not something really obvious cuz I have spent the last couple of hours trying to figure this out even though ive got the flu! lol).
import java.awt.* ;
import java.awt.event.* ;
import java.awt.geom.* ;
import javax.swing.* ;
import javax.swing.event.* ;
public class MineSweeperGUI extends JFrame implements ActionListener, MouseListener {
int width = 10;
int height = 10;
JPanel p = new JPanel();
JButton[][] table = new JButton[width][height];
public void MineSweeper() {
MinesweeperLogic logicClass = new MinesweeperLogic();
logicClass.startNewGame(width, height);
JButton[] button = new JButton[width*height];
GridLayout layout = new GridLayout (width, height) ;
p.setLayout(layout);
for(int x = 0 ; x < width ; x++) {
for(int y = 0 ; y < height ; y++) {
table[x][y] = new JButton();
table[x][y].setPreferredSize(new Dimension(25,25));
table[x][y].addMouseListener (this);
p.add(table [x] [y]);
}
}
this.add(p);
this.pack();
this.setVisible(true);
}
public void mouseClicked(MouseEvent e) {
for (int x = 0 ; x < width ; x++) {
for (int y = 0 ; y < height ; y++) {
if (e.getSource() == table[x][y]) {
if(e.getButton() == e.BUTTON1) {
MinesweeperLogic logicClass = new MinesweeperLogic();
logicClass.isOpen(x, y); //<--------------------------------------
}
}
}
}
}
public void gameover(int x, int y) {
table[x][y].setText("*");
}
public static void main(String[]args) {
MineSweeperGUI guiClass = new MineSweeperGUI();
guiClass.MineSweeper();
}}
public void actionPerformed(ActionEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public class MinesweeperLogic {
private int w, h, maxBombs, bombsremaining;
public int width, height;
private boolean mine[][];
private boolean flag[][];
private boolean isClicked[][];
private boolean isZero[][];
private boolean marked;
public void startNewGame(int width, int height) {
w = width;
h = height;
flag = new boolean[w][h];
isZero = new boolean[w][h];
isClicked = new boolean[w][h];
mine = new boolean[w][h];
maxBombs =(int) Math.floor (width*height*0.15);
bombsremaining = maxBombs;
for(int i = 0; i < maxBombs; i++) {
int x = (int) (Math.random() * (w));
int y = (int) (Math.random() * (h));
if (mine[x][y] == false) {
mine[x][y] = true;
isClicked[x][y] = false;
flag[x][y] = false;
}
}
}
int getWidth() {
return w;
}
int getHeight() {
return h;
}
boolean openCell(int x, int y) { // <---------------------------------------------
//MineSweeperGUI guiClass = new MineSweeperGUI();
isClicked[x][y] = true;
if(mine[x][y] == true && flag[x][y]==false) {
//guiClass.gameover(x, y);
return false;
} else if(neighborBombs(x, y) > 0 && flag[x][y]==false) {
return true;
} else {
marked = true;
return marked;
}}
boolean markCell(int x, int y) {
if(flag[x][y] == true) {
flag[x][y] = false;
isClicked[x][y] = false;
bombsremaining++;
marked = false;
return marked;
} else {
flag[x][y] = true;
isClicked[x][y] = true;
bombsremaining--;
if(mine[x][y]==true) {
return true;
} else {
return false;
}
}
}
boolean isOpen(int x, int y) {
if(isClicked[x][y] == false) {
return false;
} else {
return true;
}
}
boolean isMarked(int x, int y) {
if(flag[x][y] == true) {
return true;
} else {
return false;
}
}
int getValue(int x, int y) {
if(mine[x][y] == true) {
return -1;
} else {
return neighborBombs(x, y);
}
}
private int neighborBombs(int x, int y) { // checks surrounding 8 squares for number of bombs
int surBombs = 0;
for (int q = x - 1 ; q <= x + 1 ; q++) {
for (int w = y - 1 ; w <= y + 1 ; w++) {
while (true) {
if (q < 0 || w < 0 || q >= w || w >= h) {
break;
}
if (mine[q][w] == true) {
surBombs++;
break;
}
}
}
}
return surBombs;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
怎么样:
How about that:
System.out.println()
them, to see whchi one is.你的堆栈跟踪告诉你这一点:
因此,您可以转到第 117 行并确定哪些引用可能为空。 (看起来你在获取堆栈跟踪后在第 117 行添加了一行,然后注释掉了新行,所以我要在这里冒险说堆栈跟踪实际上指的是现在称为第 118 行的内容:
isClicked[x][y] = true;
) 在本例中,唯一可能为 null 的是isClicked[][]
。深入挖掘一下,我们可以看到您确实在 startNewGame() 中初始化了 isClicked,但显然该实例正在丢失。发生这种情况有两个原因:首先,构造函数中的logicClass超出了范围,因为它不是该类的成员。其次(这可能是解决第一个问题的失败尝试),在 mouseClicked 中,您创建一个新的 MinesweeperLogic (以及新创建的 null isClicked)而不是使用您之前在
MineSweeper()
构造函数中创建的那个。您还应该进行其他几项重构来清理代码,但是使logicClass成为成员并删除重复的实例化应该可以解决眼前的问题。
使用调试器并亲自解决问题以准确了解发生的情况可能会对您有所帮助。
Your stacktrace tells you this:
So you can go to line 117 and determine which references could possibly be null. (It seems like you added a line at 117 after the stacktrace was taken, and then commented out the new line, so I'm going to go out on a limb here and say the stacktrace was actually referring to what is now called line 118:
isClicked[x][y] = true;
) The only thing that could be null, in this case, isisClicked[][]
.Digging a little deeper, we can see that you do initialize isClicked in startNewGame(), but obviously that instance is getting lost. This is happening for two reasons: first, the logicClass from your constructor is going out-of-scope because it's not a member of the class. Second (and this was probably a failed attempt to fix the first problem), in
mouseClicked
, you create a newMinesweeperLogic
(along with a newly-created null isClicked) instead of using the one you previously created in yourMineSweeper()
constructor.There are several other refactorings you should make to clean up your code, but making logicClass a member and removing the duplicate instantiation should fix the immediate problem.
It might be helpful for you to use the debugger, and step through the problem yourself to understand exactly what is happening.
数组(flag、isZero、isClicked)未初始化,当您尝试使用它们时它们为空。您需要 GUI 类包含逻辑类的实例并始终使用同一实例。否则,每个 GUI 操作都将发生在不同的游戏上!
The arrays (flag, isZero, isClicked) are not initialized and are null when you try and use them. You need the GUI class to contain an instance of the logic class and always use that same instance. Otherwise, each GUI action will take place on a different game!
了解逻辑类中的第 117 行是什么会很有帮助。我的猜测是
mine
、mine[x]
、flaged
或flagged[x]
为 null。也就是说,您“遍历整个表格以查看单击了哪一个”的技术并没有给我带来特别的启发。
编辑:实际上,问题是 isOpen 数组为空,因为您刚刚实例化了该类。
EDIT2:好的,这是我最初列出的其中之一。我的猜测是全部,因为您刚刚实例化了该类,并且它使用默认的不执行任何操作的构造函数。
It would be helpful to know what line number 117 in the logic class was. My guess would be either
mine
,mine[x]
,flagged
orflagged[x]
is null.That said, your technique of "loop through the entire table to see which one was clicked" doesn't strike me as particularly inspired.
EDIT: Actually, the problem is that the
isOpen
array is null, because you've only just instantiated the class.EDIT2: Alright, so it's one of the ones I listed initially. My guess would be all of them, because you've only just instantiated the class, and it's using the default do-nothing constructor.
您说错误发生在 mouseClicked() 方法中,但是堆栈跟踪显示不同:
这表明 NPE 发生在 MineSweeperLogic 的第 117 行。在该行上使用调试器,或者插入打印语句来找出空值,从那里,您可以找出原因。
You say that the error occurs in the mouseClicked() method, however the stacktrace shows differently:
This is saying that the NPE occured on line 117 of MineSweeperLogic. Use either your debugger on that line, or insert print statements to work out what is null, from there, you can work out why.
请注意,您可能会在
myMethod(myNumber);
之类的行上遇到此异常,因为自动拆箱是“myNumber”是 Long 类型,但当前为 null。希望 JVM 能更好地报告这一点。修复方法是不传入 null,它不会自动转换为零......
As a note, you can get this exception on a line like this
myMethod(myNumber);
due to auto-unboxing is "myNumber" is a type Long but is currently null. Wish the JVM reported this better. Fix is to not pass in null, which isn't auto converted to zero...