Ссылочная переменная для объекта, созданного / инициализированного в другом классе в Java - PullRequest
1 голос
/ 11 января 2011

Причина, по которой я спрашиваю, в том, что я получаю исключение NullPointerException.Я сейчас это очень легко, но я довольно новое программирование и нахожу это немного запутанным.Допустим, я инициализировал объект в классе и хочу получить доступ к тому же объекту из другого класса.

Как, например, сейчас я работаю над небольшой игрой в шахматы, в моей модели класса Game у меня есть экземплярдоски, объект.Доска, в свою очередь, имеет массив квадратов.Квадрат [] [].

В игре есть доска, у доски есть Квадрат [] [].

Теперь, если я хочу получить доступ к Квадрату [] [] через игровое поле (в игре)типа платы.Должен ли я просто объявить переменную с тем же именем и типом, или мне нужно заново ее инициализировать?

Board board ИЛИ Board board = new Board ();

Примечание. Я уже инициализировандоска в классе Game, так что, если я сделаю это снова, не будут ли они двумя совершенно разными объектами Board?

Класс, который ссылается на «доску»:

public class View extends JFrame {

Board      board;
JFrame     gameWindow   = new JFrame("Chess");
JPanel     gamePanel    = new JPanel();
JPanel[][] boardPanel   = new JPanel[8][8];
JMenuBar   gameMenu     = new JMenuBar();
JButton    newGame      = new JButton("New game");
JButton    pauseGame    = new JButton("Pause");
JButton    actionLog    = new JButton("Action log");

View(){
    gameWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
    gameWindow.setSize(400, 400);
    gameWindow.getContentPane().add(gamePanel);
    gameWindow.setVisible(true);
    gamePanel.setVisible(true);
    gameMenu.add(newGame);
    gameMenu.add(pauseGame);
    gameMenu.add(actionLog);
    for(JPanel[] row : boardPanel){
        for(JPanel box : row){
            gamePanel.add(box);
        }
    }
}

public void drawBoard(){
    for(int y = 0; y < 8; y++){
        for(int x = 0; x < 8; x++){
            Box box = new Box();
            box.setColour(board.getSquare(x, y).getColour());
            box.setCol(x);
            box.setRow(y);
            box.repaint();
            boardPanel[x][y].add(box);
        }
    }
}

}

class Box extends JComponent{
JPanel[][] boardPanel;
Board board;
Color boxColour;
int col, row;
public Box(){
    repaint();
}
public void paint(Graphics drawBox){
    drawBox.setColor(boxColour);
    drawBox.drawRect(50*col, 50*row, 50, 50);
    drawBox.fillRect(50*col, 50*row, 50, 50);
}
public void setColour(Color boxColour){
    this.boxColour = boxColour;
}

public void setCol(int col){
    this.col = col;
}

public void setRow(int row){
    this.row = row;
}

}

... и класс, который создает экземпляр "board":

public class Game {

@SuppressWarnings("unused")
public static void main(String[] args) 
        throws Throwable{
    Board board = new Board();
    View view = new View();
}

}

Исключение происходит здесь:

        for(JPanel[] row : boardPanel){
        for(JPanel box : row){
            gamePanel.add(box);
        }
    }

Ответы [ 5 ]

3 голосов
/ 12 января 2011

Обратите внимание, я уже инициализировал доску в классе Game, так что, если я сделаю это снова, не будут ли они двумя совершенно разными объектами Board?

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

Теперь, если я хочу получить доступ к Квадрату [] [] через игровое поле (в игре) типа Board. Должен ли я просто объявить переменную с тем же именем и типом, или мне нужно снова ее инициализировать?

У вас есть 2 способа предоставить Game доступ к квадратам (возможно, больше, чем 2, в зависимости от того, как вы на это смотрите):

1 Попросите Правление предоставить доступ к Квадратам (например, метод получения на плате, который возвращает массив Квадратов), чтобы Game мог получить к ним доступ. Затем Board может сохранить ссылку (иметь собственную переменную экземпляра для хранения ссылки на квадраты или может каждый раз запрашивать ссылку у Board).

2 Попросите Правление предоставить методы, которые делают то, что Игра хочет сделать на квадратах, то есть игра просит, чтобы доска сделала что-то с квадратами, а доска выполняет действие на квадратах.

1 голос
/ 12 января 2011

Причина NPE заключается в том, что поле board в классе View фактически не инициализировано.Когда вы объявляете поле, если вы не предоставляете инициализатор по умолчанию, оно инициализируется как null, поэтому оператор Board board; объявляет поле board, которое ссылается на null.

. Выможно было бы устранить NPE, вместо этого объявив Board board = new Board();, но это создаст новый экземпляр, а это не то, что вам нужно.Вместо этого здесь есть два варианта:

  1. Добавить метод получения и установки для поля board в классе View и вызвать его из основного метода:

    public class View extends JFrame {
        Board      board;
        // ...
    
        public Board getBoard() { return board; }
        public void setBoard(Board b) { this.board = b; }
    }
    
    public class Game {
        @SuppressWarnings("unused")
        public static void main(String[] args) 
            throws Throwable{
        Board board = new Board();
        View view = new View();
        view.setBoard(board);
    }
    

    }

  2. Передайте параметр в конструктор, если вам нужен доступ к объекту из конструктора:

    public class View extends JFrame {
        Board      board;
        // ...
    
        View(Board b) {
            this.board = b;
            // ...
        }
    }
    
    public class Game {
        @SuppressWarnings("unused")
        public static void main(String[] args) 
            throws Throwable{
        Board board = new Board();
        View view = new View(board);
    }
    

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

0 голосов
/ 12 января 2011

Экземпляр Board, который вы создаете в своем методе main (), отличается от экземпляра board экземпляра вашего класса View. Вид имеет следующее:

public class View extends JFrame { 
  Board      board;
  ...

Этой переменной плате никогда не присваивается значение (то есть новая доска ())

Затем в основном методе вашего класса Game вы объявляете новую доску и новый вид:

Board board = new Board();
View view = new View();

Эта переменная board является локальной переменной основного метода и не имеет отношения к переменной экземпляра board в вашем представлении. В вашем классе View вам нужно изменить объявление переменной на:

Board board = new Board();
0 голосов
/ 12 января 2011

Это 2 разных объекта. Вы не должны получать NPE, если у вас есть их новые. Может быть, ваш фрагмент кода поможет здесь обнаружить NPE или трассировка стека NPE тоже поможет.

Board board1 = new Board(); //creates a new Board object 
Board board2 = new Board(); //creates another new Board object
0 голосов
/ 11 января 2011

NPE вызвано тем, что объект не был создан.Таким образом, решение требует инстанцирования.Вы делаете это с новым оператором, поэтому новый Board ()

...