I wrote a program for Conway's Game Of Life in Java. Are there any improvements I could make?

main class:

```
package main;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;

public class GameOfLife {

    static Board board;
    static Window window;
    static Input input = new Input();
    static BufferStrategy bs;

    //board and window setup
    public static void start() {
        window = new Window("game", 800, 500);
        board = new Board(window.getCanvas().getWidth(), window.getCanvas().getHeight());
        board.setUp();
    }

    //renders the board
    public static void render() {
        bs = window.getCanvas().getBufferStrategy();
        if(bs == null) {
            window.getCanvas().createBufferStrategy(2);
        }
        bs = window.getCanvas().getBufferStrategy();

        window.getCanvas().setBackground(Color.black);
        window.requestFocusInWindow();
        Graphics2D g2d = (Graphics2D) bs.getDrawGraphics();

        g2d.clearRect(0, 0, window.getCanvas().getWidth(), window.getCanvas().getHeight());

        g2d.setColor(Color.white);
        for (int i = 0; i < board.getBoard().length; i++) {
            for (int j = 0; j < board.getBoard()[0].length; j++) {
                if (board.getState(i, j, board.getBoard())) {
                    g2d.fillRect(i * board.getCellSize(), j * board.getCellSize(), board.getCellSize(),
                            board.getCellSize());
                }
            }
        }

        g2d.dispose();
        bs.show();
    }

    //timing for framerate
    public static void pause(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //main loop
    public static void main(String[] args) {
        start();
        while(true) {
            long start = System.nanoTime();

            if(!input.getPaused()) {
                board.updateBoard();
            }
            render();

            long deltatime = (System.nanoTime() - start) / 1000000;

            if((16 - deltatime) >= 0) {
                pause(16 - deltatime);
            }
        }
    }

}

```

board class:

```
package main;

import java.util.Random;

public class Board {

    private boolean[][] board;
    private boolean[][] newboard;
    int cellsize = 4;
    Random random = new Random();

    public Board(int width, int height) {
        board = new boolean[width/cellsize][height/cellsize];
        newboard = new boolean[width/cellsize][height/cellsize];
    }

    //getters and setters
    public boolean[][] getBoard() {
        return this.board;
    }

    public boolean getState(int x, int y, boolean[][] board) {
        if(x < 0 || y < 0 || x > board.length-1 || y > board[0].length-1) {
            return false;
        }
        return board[x][y];
    }

    public int getCellSize() {
        return this.cellsize;
    }

    //counts number of alive cells next to cell
    public int countNeighbours(int x, int y) {
        int count = 0;

        for(int i = x-1; i <= x+1; i++) {
            for(int j = y-1; j <= y+1; j++) {
                if(i != x || j != y) {
                    if (getState(i, j, board)) {
                        count++;
                    }
                }
            }
        }

        return count;
    }

    //returns state of cell in the next generation
    public boolean getNewState(int x, int y) {
        int count = countNeighbours(x, y);
        boolean state = getState(x, y, board);

        if(state && count > 1 && count < 4) {
            return true;
        }
        else if(!state && count == 3) {
            return true;
        }

        return false;
    }

    //changes states to those of the next generation
    public void updateBoard() {
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[i].length; j++) {
                newboard[i][j] = getNewState(i, j);
            }
        }

        for(int x = 0; x < newboard.length; x++) {
            for(int y = 0; y < newboard[x].length; y++) {
                board[x][y] = getState(x, y, newboard);
            }
        }
    }

    //assigns every cell a random state
    public void setUp() {
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[i].length; j++) {
                board[i][j] = random.nextBoolean();
            }
        }
    }
}

```

window class:

```
package main;

import java.awt.Canvas;
import java.awt.Point;

import javax.swing.JFrame;

public class Window extends JFrame {

    private static final long serialVersionUID = 1L;
    private Canvas canvas;
    static Input input = new Input();

    //window setup
    public Window(String title, int width, int height) {
        setSize(width, height);
        setTitle(title);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setResizable(false);
        setLocation(new Point(0, 0));
        setVisible(true);

        canvas = new Canvas();
        canvas.setSize(width, height);
        canvas.setFocusable(true);

        add(canvas);
        addKeyListener(input);
    }

    //getters and setters
    public Canvas getCanvas() {
        return canvas;
    }

    public void setCanvas(Canvas canvas) {
        this.canvas = canvas;
    }

}

```

input class:

```
package main;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Input implements KeyListener {

    private static boolean paused;

    public Input() {

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_SPACE) {
            paused = !paused;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    //getters and setters
    public boolean getPaused() {
        return paused;
    }

}

```