Исключение NullPointer при вызове метода из разностного класса - PullRequest
1 голос
/ 16 декабря 2009

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)

Наконец, весь (хотя и неполный на данный момент) код для двух классов, если это необходимо. (Методы в классе логики требуются для выполнения определенных действий в соответствии с инструкциями проекта и не должны взаимодействовать с пользователем в классе логики). Я не могу понять, что именно вызывает ошибку. Любое руководство будет с благодарностью. (надеюсь, это не что-то действительно очевидное, потому что я провел последние пару часов, пытаясь выяснить это, хотя у меня был грипп! 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;
        }
    }

Ответы [ 5 ]

11 голосов
/ 16 декабря 2009

Как насчет этого:

  1. посмотрите на первую строку вашей трассировки стека исключений и посмотрите, с каким классом и с какой строкой возникает проблема
  2. перейдите к этой строке и посмотрите, какие объекты могут быть "нулевыми" в этом месте
  3. выясните, почему объекту, который является нулевым, не присвоено значение
  4. если есть несколько объектов, которые могут быть нулевыми, вы можете System.out.println() их увидеть, какой из них есть.
4 голосов
/ 16 декабря 2009

Ваша трассировка стека говорит вам следующее:

Исключение в потоке "AWT-EventQueue-0" java.lang.NullPointerException в MinesweeperLogic.isOpen (MinesweeperLogic.java:117)

Таким образом, вы можете перейти к строке 117 и определить, какие ссылки могут быть нулевыми. (Похоже, вы добавили строку на 117 после того, как трассировку стека взяли, а затем закомментировали новую строку, так что я собираюсь выйти здесь на конечность и сказать, что на самом деле трассировка стека ссылалась на то, что теперь называется строкой 118 : isClicked[x][y] = true;) В данном случае единственное, что может быть нулевым, это isClicked[][].

Копая немного глубже, мы видим, что вы инициализируете isClicked в startNewGame (), но, очевидно, этот экземпляр теряется. Это происходит по двум причинам: во-первых, logicClass из вашего конструктора выходит из области видимости, потому что он не является членом класса. Во-вторых (и это, вероятно, неудачная попытка решить первую проблему), в mouseClicked вы создаете новый MinesweeperLogic (вместе с вновь созданным нулевым isClicked) вместо того, чтобы использовать тот, который вы ранее создали в вашем MineSweeper() конструктор.

Существует несколько других рефакторингов, которые вы должны выполнить, чтобы очистить свой код, но создание логического класса в качестве члена и удаление дублирующихся экземпляров должно решить непосредственную проблему.

Для вас может оказаться полезным использовать отладчик и самостоятельно разобраться с проблемой, чтобы точно понять, что происходит.

2 голосов
/ 16 декабря 2009

Массивы (flag, isZero, isClicked) не инициализируются и являются нулевыми, когда вы пытаетесь их использовать. Класс GUI должен содержать экземпляр класса логики и всегда использовать тот же экземпляр. В противном случае каждое действие GUI будет происходить в другой игре!

0 голосов
/ 16 декабря 2009

Вы говорите, что ошибка возникает в методе mouseClicked (), однако трассировка стека показывает по-другому:

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

Это говорит о том, что NPE произошел на линии 117 MineSweeperLogic. Используйте либо отладчик в этой строке, либо вставьте операторы print, чтобы выяснить, что является нулем, оттуда вы можете понять, почему.

0 голосов
/ 16 декабря 2009

Было бы полезно узнать, какой была строка с номером 117 в классе логики. Мое предположение будет либо mine, mine[x], flagged или flagged[x] равно нулю.

Тем не менее, ваша техника "перебрать всю таблицу, чтобы увидеть, на какую из них нажали", меня не особенно вдохновляет.

РЕДАКТИРОВАТЬ: На самом деле проблема в том, что массив isOpen имеет значение null, потому что вы только что создали экземпляр класса.

РЕДАКТИРОВАТЬ2: Хорошо, так что это один из тех, что я перечислил изначально. Я думаю, все они , потому что вы только что создали экземпляр класса, и он использует конструктор по умолчанию, ничего не делающий.

...