简体   繁体   中英

java Null Pointer Exception passing object

I have some class which creates a Ship (class Ship extends GameObject) and attempts to add it to a gameBoard.
To do this, it tells the gameFrame to add the object as follows:

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

The gameFrame then calls:

GameBoard gameBoard = new GameBoard();
...
...
public void addGameObject(GameObject ob) {
    gameBoard.addGameObject(ob);
}

Which in turn calls:

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

Now my problem is that I receive a Null Pointer Exception when I gameFrame.addGameObject(myShip);
The tricky thing is when I run via debugger I do not receive the NPE at all (but my objects list still seems empty).
Also, I can follow into each of these and still see myShip, so am I just referencing my GameObject (Ship) wrong?
Should my parameters for addGameObject somehow be more abstract?

The problem is that you are assigning gameFrame inside of the Runnable , which does not get run until later. So gameFrame may be null at the point you call gameFrame.addGameObject(myShip)

The problem probably is the invokeLater you use, that is scheduled whenever Swing feels like it and probably happens after gameFrame.addGameObject(myShip);

This doesnt happen in the debugger because it is somewhat of a race condition, in the debugger Swing invokes the runmethod before gameFrame.addGameObject(myShip) because you can't click fast enough to preemt that statement ;)

The best solution to this problem is to move those statements inside the run method, like this:

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

Doing it this way, the 4 statements will be run in the expected order, and the attribute will not be null when required.

check the scope where you initialized that variable. ie the curly braces { } around the new InvadersGameFrame(). Make sure you are using the object after creating it

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM