【问题标题】:Reference variable to an object instantiated/initialized in another class in Java在 Java 中的另一个类中实例化/初始化的对象的引用变量
【发布时间】:2014-11-09 14:18:12
【问题描述】:

我问的原因是因为我得到了 NullPointerException。 我现在这很容易,但我是一个非常新的编程,发现这有点令人困惑。 假设我已经在一个类中初始化了一个对象,并想从另一个类访问同一个对象。

例如,我正在开发一个小型国际象棋游戏,在我的模型 Game 类中,我有一个 Board 实例,一个对象。反过来,Board 有一系列 Squares。方[][]。

游戏有棋盘,棋盘有 Square[][]。

现在,如果我想通过 Board 类型的对象板(在游戏中)访问 Square[][]。 我只是声明一个具有相同名称和类型的变量还是必须再次初始化它?

Board board OR 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);
        }
    }

【问题讨论】:

  • 你能把代码放在这里吗?带有定义的位置。

标签: java reference initialization nullpointerexception


【解决方案1】:

NPE 是由未实例化的对象引起的。所以解决它需要实例化。您使用 new 运算符执行此操作,因此 new Board()

【讨论】:

  • 哦,好吧,但这就是我感到困惑的地方。我已经在我的一个类中实例化了它,我想使用那个特定的对象。如果我再次实例化它,它不会创建一个不同的对象吗?我的意思是,我已经有了 Board board = new Board();在我的一个类中,比如说 A 类。如果我在 B 类中使用 Board board = new Board() 再次实例化它,然后使用引用“board”,它会引用与 A 类中相同的实例吗?
  • 这取决于您在哪里定义作为范围的板变量
  • 它不依赖于范围。它们是完全不同的对象。如果你想每次都访问同一个板对象,你可以使用单例模式。
  • 错误答案。 NPE 是由空引用引起的。创建一个新实例远非设置对 null 以外的引用的唯一方法。
  • @Navi: String a = "hello"; String b = a 你是说b 现在是空的吗?您可以使用赋值运算符来分配对 any 对象的引用,而不仅仅是内联创建的新实例。
【解决方案2】:

NPE 的原因是 View 类中的 board 字段实际上没有初始化。当你声明一个字段时,如果你默认不提供初始化器,它会被初始化为null,所以Board board;声明了一个引用null的字段board

您可以通过声明 Board board = new Board(); 来消除 NPE,但这会创建一个新实例,这不是您想要的。相反,这里有两个选项:

  1. 为 View 类中的 board 字段添加 getter 和 setter,并从 main 方法中调用:

    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 提到的单例模式,但我更愿意尽可能避免使用它,因为如果你后来决定确实需要多个类的实例,那么撤销它可能会很痛苦。

【讨论】:

  • 谢谢!好答案。我将它作为参数传递给 View 中实际需要它的方法。不过,我仍然从另一个来源获得 NPE。似乎找不到问题所在,所以我可能会在这里问另一个问题。
【解决方案3】:

它们是 2 个不同的对象。如果你有新的,你不应该得到 NPE。可能您的代码 sn-p 将有助于检测 NPE,或者 NPE 的堆栈跟踪也会有所帮助。

Board board1 = new Board(); //creates a new Board object 
Board board2 = new Board(); //creates another new Board object

【讨论】:

    【解决方案4】:

    注意,我已经在 Game 类中初始化了棋盘,所以如果我再做一遍,它们会不会是两个完全不同的棋盘对象?

    是的,您将拥有两个完全不同的实例。你得到了基本的想法——你的程序中有对象的实例,现在你必须让它们一起工作。

    现在,如果我想通过 Board 类型的对象板(在游戏中)访问 Square[][]。我只是声明一个具有相同名称和类型的变量还是必须再次初始化它?

    您有 2 种方法可以让 Game 访问方块(可能不止 2 种,具体取决于您如何看待它):

    1 让 Board 提供对 Squares 的访问(例如,Board 上的 getter 方法返回 Squares 数组),以便 Game 可以访问它们。然后 Board 可以保存引用(有自己的实例变量来保存对 squares 的引用,或者可以每次都向 Board 询问引用)。

    2 让棋盘提供方法来执行游戏想要在方格上做的事情,即游戏要求棋盘对方格做某事,棋盘在方格上执行动作。

    【讨论】:

    • 哦,但是 Game 可以访问 Board 和 Squares。游戏有一个 Board 实例。我的意思是我试图将模型与 gui 分开,我需要在我的 gui 类中引用“board”,即 Game 中的相同实例。
    • 迄今为止的最佳答案。我要补充一点,上面给出的选项(2)似乎更合适。游戏不应该直接访问 Squares,它应该调用 Board 来间接操纵它们。
    • @Alex -- 为了让这个答案与您的具体问题更相关,您可能会选择选项 (1),这意味着 Game 应该有一个 getBoard() 方法来返回其棋盘参考。
    • 好的,谢谢。如果你不介意我问,那有什么用?我是否应该在我的 View 类中创建一个 Game 实例来访问板,然后在我的 Game 类中创建一个 View 实例来提供 GUI?
    • @Alex - 遵循 MVC 的原则,您的模型类(Board 和 Square)不应该知道任何 GUI/视图类,但视图类可以知道模型类。至于创建实例,我会在你的 main 方法中创建一个 Game 的实例,然后在你在 main 方法中创建 View 的实例时将游戏传递给视图的构造函数。然后视图可以保持对游戏的引用作为实例变量。
    【解决方案5】:

    您在 main() 方法中创建的 Board 实例与 View 类的实例变量 board 不同。视图有以下内容:

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

    这个变量板永远不会被赋值(即一个新的 Board())

    然后,在 Game 类的 main 方法中,声明一个新的 Board 和一个新的 View:

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

    这个变量board是main方法的局部变量,和你View中的实例变量board没有关系。在您的 View 类中,您需要将变量声明更改为:

    Board board = new Board();
    

    【讨论】:

      猜你喜欢
      • 2013-08-14
      • 2014-11-01
      • 2013-07-04
      • 1970-01-01
      • 2021-05-11
      • 2015-05-17
      • 2011-06-21
      • 2022-11-20
      相关资源
      最近更新 更多