java 从差异类调用方法时出现 NullPointer 异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1917384/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 18:30:58  来源:igfitidea点击:

NullPointer Exception when calling method from a difference class

javanullpointerexceptionmethod-call

提问by newBie01

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:

JAVA-嗨,我正在编写一个扫雷程序(第一个大人物)并且我真的被卡住了。根据我要遵循的规范,程序本身由 2 个类(一个用于逻辑,一个用于 GUI)组成。我在这两门课上都做了很多,但也没有完成。但是,我正在尝试测试从一个类到另一个类的调用方法的实现,这就是我卡住的地方。从 GUI 类中,每次用户单击一个框时,我都试图在 Logic 类中调用 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;
    }}

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

回答by Bozho

How about that:

那个怎么样:

  1. look at the first line of your exception stacktrace, and see which class and which line the problem occurs
  2. go to that line, and see which objects could possibly be "null" at this location
  3. find out why the object that is null doesn't have a value assgined
  4. if there are more than one objects that could be null, you could System.out.println()them, to see whchi one is.
  1. 查看您的异常堆栈跟踪的第一行,并查看问题发生在哪个类和哪一行
  2. 转到该行,查看在此位置哪些对象可能为“空”
  3. 找出为什么 null 的对象没有分配的值
  4. 如果有多个对象可能为空,您可以使用System.out.println()它们,看看是哪个对象。

回答by rob

Your stacktrace tells you this:

您的堆栈跟踪告诉您:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at MinesweeperLogic.isOpen(MinesweeperLogic.java:117)

线程“AWT-EventQueue-0”中的异常 java.lang.NullPointerException at MinesweeperLogic.isOpen(MinesweeperLogic.java:117)

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, is isClicked[][].

因此,您可以转到第 117 行并确定哪些引用可能为空。(似乎您在获取堆栈跟踪后在 117 处添加了一行,然后注释掉了新行,所以我要在这里断言,堆栈跟踪实际上指的是现在称为第 118 行的内容:isClicked[x][y] = true;)这可能是空的唯一的事情,在这种情况下,是isClicked[][]

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 new MinesweeperLogic(along with a newly-created null isClicked) instead of using the one you previously created in your MineSweeper()constructor.

深入一点,我们可以看到您确实在 startNewGame() 中初始化了 isClicked,但显然该实例正在丢失。发生这种情况有两个原因:首先,构造函数中的 logicClass 超出范围,因为它不是类的成员。其次(这可能是解决第一个问题的失败尝试),在 中mouseClicked,您创建了一个新的MinesweeperLogic(以及一个新创建的 null isClicked),而不是使用您之前在MineSweeper()构造函数中创建的那个。

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.

您应该进行其他一些重构来清理代码,但是将 logicClass 设为成员并删除重复的实例化应该可以解决当前的问题。

It might be helpful for you to use the debugger, and step through the problem yourself to understand exactly what is happening.

使用调试器并自己逐步解决问题以准确了解正在发生的事情可能会对您有所帮助。

回答by tster

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!

数组(flag、isZero、isClicked)未初始化并且在您尝试使用它们时为空。您需要 GUI 类包含逻辑类的实例并始终使用相同的实例。否则,每个 GUI 动作都会发生在不同的游戏中!

回答by Anon.

It would be helpful to know what line number 117 in the logic class was. My guess would be either mine, mine[x], flaggedor flagged[x]is null.

知道逻辑类中的第 117 行是什么会很有帮助。我的猜测是,要么minemine[x]flaggedflagged[x]为空。

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 isOpenarray is null, because you've only just instantiated the class.

编辑:实际上,问题在于isOpen数组为空,因为您刚刚实例化了该类。

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.

EDIT2:好的,所以它是我最初列出的之一。我的猜测是所有这些,因为您刚刚实例化了该类,并且它使用了默认的什么都不做的构造函数。

回答by Paul Wagland

You say that the error occurs in the mouseClicked() method, however the stacktrace shows differently:

您说该错误发生在 mouseClicked() 方法中,但是堆栈跟踪显示不同:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
 at MinesweeperLogic.isOpen(MinesweeperLogic.java:117)
 at MineSweeperGUI.mouseClicked(MineSweeperGUI.java:126)

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.

这就是说 NPE 发生在 MineSweeperLogic 的第 117 行。在该行使用您的调试器,或插入打印语句来计算什么是空值,从那里,您可以找出原因。