Исключение указателя java
У меня есть некоторый класс, который создает корабль (класс Ship расширяет GameObject) и пытается добавить его в gameBoard.
Для этого он сообщает gameFrame добавить объект следующим образом:
public void startNewGame() {
Ship myShip = new Ship(GAME_BOARD_WIDTH / 2, GAME_BOARD_HEIGHT-1, SHIP_WIDTH,
SHIP_HEIGHT);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gameFrame = new InvadersGameFrame();
}
});
gameFrame.addGameObject(myShip); //Problem line
gameFrame.repaint();
}
Затем GameFrame вызывает:
GameBoard gameBoard = new GameBoard();
...
...
public void addGameObject(GameObject ob) {
gameBoard.addGameObject(ob);
}
Который в свою очередь называет:
public class GameBoard extends JPanel implements GameData{
private JPanel gameBoard;
private List<GameObject> objects = new ArrayList<>();
public GameBoard() {
gameBoard = new JPanel();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.black);
g.setColor(Color.RED);
for(GameObject ob : objects){
g.drawOval(ob.x, ob.y, ob.width, ob.height);
}
}
//Places object into list for drawing upon next repaint.
public void addGameObject(GameObject ob) {
objects.add(ob);
}
}
Теперь моя проблема в том, что я получаю исключение нулевого указателя, когда я gameFrame.addGameObject(myShip);
Сложность в том, что когда я запускаю через отладчик, я вообще не получаю NPE (но мой список объектов все еще кажется пустым).
Кроме того, я могу следить за каждым из них и по-прежнему видеть мой корабль, так что я просто неправильно ссылаюсь на свой GameObject (Ship)?
Должны ли мои параметры для addGameObject быть более абстрактными?
4 ответа
Проблема в том, что вы назначаете gameFrame
внутри Runnable
, который не запускается до позднего времени. Так gameFrame
может быть нулевым в точке вызова gameFrame.addGameObject(myShip)
Возможно, проблема в используемом вами invokeLater, который запланирован всякий раз, когда Swing чувствует себя так, как это происходит, и, вероятно, происходит после gameFrame.addGameObject(myShip);
Этого не происходит в отладчике, потому что это отчасти гоночное состояние, в отладчике Swing вызывает метод выполнения перед gameFrame.addGameObject (myShip), потому что вы не можете щелкнуть достаточно быстро, чтобы предопределить этот оператор;)
Лучшее решение этой проблемы - переместить эти утверждения в run
метод, как это:
public void startNewGame() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Ship myShip = new Ship(GAME_BOARD_WIDTH / 2, GAME_BOARD_HEIGHT-1,
SHIP_WIDTH, SHIP_HEIGHT);
gameFrame = new InvadersGameFrame();
gameFrame.addGameObject(myShip); //Problem line
gameFrame.repaint();
}
});
}
Делая это таким образом, 4 оператора будут выполняться в ожидаемом порядке, а атрибут не будет null
когда требуется.
Проверьте область, где вы инициализировали эту переменную. т.е. фигурные скобки { } вокруг нового InvadersGameFrame(). Убедитесь, что вы используете объект после его создания