違いクラスからメソッドを呼び出すときのnullpointer例外
-
20-09-2019 - |
質問
Java-こんにちは、私はMinesweeperプログラム(First Biggie)を書いていますが、本当に立ち往生しています。プログラム自体は、私が従うべき仕様に従って、2つのクラス(ロジック用、もう1つはGUI用)で構成されています。私は両方のクラスでかなりのことをしましたが、どちらも終了していません。しかし、私は一方のクラスから別のクラスにコールメソッドの実装をテストしようとしていますが、それが私が立ち往生する場所です。 GUIクラスから、ユーザーがボックスをクリックするたびに、ロジッククラスのメソッドOpenCell(int x、int y)を呼び出しようとしています。そのロジッククラスのメソッドは、順番に鉱山、0、または正方形に数字があるかどうかを確認し、GUIクラスの適切な方法を呼び出します。エラーに含まれる2つの方法は次のとおりです。
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)
最後に、必要に応じて、これまでに2つのクラスのコード(この時点で不完全)全体がコードされます。 (ロジッククラスのメソッドは、プロジェクトの指示に従って特定のアクションを実行するために必要であり、ロジッククラスでユーザーインタラクションは必要ありません)。何が正確にエラーを引き起こしているのかを理解できません。どんなガイダンスも大歓迎です。 (うまくいけば、それは本当に明白なものではないので、私はこれを理解しようとして私がここ数時間を費やしたので、私はインフルエンザにかかっていても!笑)。
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;
}
}
解決
どのようにそのことについて:
- 例外Stacktraceの最初の行を見て、どのクラスとどの線が発生するかを確認してください
- その行に移動して、この場所でどのオブジェクトが「ヌル」になる可能性があるかを確認してください
- nullであるオブジェクトが値を持っていない理由を見つけてください
- nullになる可能性のあるオブジェクトが複数ある場合は、
System.out.println()
彼らは、whchiがあるのを見るために。
他のヒント
あなたのスタックトレースはあなたにこれを教えてくれます:
スレッド「AWT-EVENTQUEUE-0」の例外java.lang.nullpointerexception minesweeperlogic.isopen(minesweeperlogic.java:117)
したがって、117行に移動して、どの参照がnullになる可能性があるかを判断できます。 (Stacktraceが撮影された後、117にラインを追加してから新しいラインをコメントしたように思われますので、ここで手足に出て、Stacktraceが実際に現在118行と呼ばれるものを参照していたと言います。 : isClicked[x][y] = true;
)この場合、ヌルになる可能性のある唯一のことは、 isClicked[][]
.
もう少し深く掘り下げると、startnewgame()でIsclickedを初期化することがわかりますが、明らかにそのインスタンスは失われています。これは2つの理由で起こっています。まず、コンストラクターからのロジッククラスは、クラスのメンバーではないため、スコープが外れています。 2番目(そして、これはおそらく最初の問題を修正するための失敗した試みでした)、 mouseClicked
, 、新しいものを作成します MinesweeperLogic
(新しく作成されたnullとともに、クリックされています)以前に作成したものを使用する代わりに MineSweeper()
コンストラクタ。
コードをクリーンアップするには他にもいくつかのリファクタリングがありますが、LogicClassをメンバーにして重複するインスタンス化を削除すると、即時の問題が解決するはずです。
デバッガーを使用し、問題を自分で踏み出して、何が起こっているのかを正確に理解することは役立つかもしれません。
配列(フラグ、Iszero、isclicked)は初期化されず、試して使用するとnullです。 Logicクラスのインスタンスを含め、常に同じインスタンスを使用するには、GUIクラスが必要です。それ以外の場合、各GUIアクションは別のゲームで行われます!
Logicクラスの数字117が何であったかを知ることは役立ちます。私の推測もどちらかです mine
, mine[x]
, flagged
また flagged[x]
無効です。
とはいえ、「テーブル全体をループして、どのものがクリックされたかを確認する」というテクニックは、特にインスピレーションを与えてくれません。
編集:実際、問題は次のことです isOpen
アレイはnullです。クラスをインスタンスしたばかりなので。
edit2:大丈夫、それは私が最初にリストしたものの1つです。私の推測はでしょう それらすべて, 、クラスをインスタンス化したばかりで、デフォルトのdo-notingコンストラクターを使用しているためです。
エラーはMouseClicked()メソッドで発生すると言いますが、スタックトレースは異なって表示されます。
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at MinesweeperLogic.isOpen(MinesweeperLogic.java:117)
at MineSweeperGUI.mouseClicked(MineSweeperGUI.java:126)
これは、NPEがMinesweeperLogicの117行目で発生したと言っています。そのラインでデバッガーのいずれかを使用するか、印刷ステートメントを挿入して、nullとは何かを作成します。そこから、理由を解決できます。