You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX中UserController的ArrayList非空却触发空指针异常问题

问题根源分析

你遇到的NullPointerException核心原因是FXMLLoader创建了一个独立的UserInterface实例,和你在start()方法中操作的不是同一个对象。具体来说:

  1. 当你调用FXMLLoader.load(getClass().getResource("login.fxml"))时,FXMLLoader会读取fxml中的fx:controller="classmanager.UserInterface"配置,自动创建一个全新的UserInterface实例作为页面控制器。
  2. 你在start()方法中初始化的userController,并调用setUserList()赋值的操作,都是在Application自身的UserInterface实例上完成的,和FXMLLoader创建的控制器实例完全无关。
  3. 当按钮触发login()方法时,实际调用的是FXMLLoader创建的那个UserInterface实例的login()方法,它内部的userController是全新初始化的,从未执行过setUserList(),所以userList自然是null,导致空指针异常。

而使用static ArrayList<User> userList能解决问题,是因为静态变量属于类本身,所有实例共享——之前的实例设置了静态userList后,新实例的userController也能访问到这个值,但这是一种不规范的 workaround,会带来状态管理混乱、内存泄漏等风险,不推荐使用。

解决方案

方案1:分离Application和FXML控制器(推荐)

将页面逻辑和Application启动逻辑分开,避免一个类身兼两职:

  1. 创建独立的LoginController作为login.fxml的控制器:
public class LoginController {
    UserController userController = new UserController();

    @FXML public TextField InputEmailAddress;
    @FXML public TextField InputPassword;

    public void setUserController(UserController controller) {
        this.userController = controller;
    }

    public void login(ActionEvent event) throws Exception {
        userController.login();
    }
}
  1. 修改login.fxml的控制器配置:
<Pane ... fx:controller="classmanager.LoginController">
    <!-- 其他控件不变 -->
</Pane>
  1. 在UserInterface的start()方法中,加载FXML时获取控制器实例并传递已初始化的userController:
@Override
public void start(Stage stage) throws Exception {
    String connectionURL = "jdbc:derby://localhost:1527/gymManager";
    String userName = "root";
    String userPassword= "root";
    try {
        conn = DriverManager.getConnection(connectionURL, userName, userPassword);
        if(conn != null){
            System.out.println("Connected to the database");
            ArrayList<User> list = userRepo.read(conn);
            UserController userController = new UserController();
            userController.setUserList(list);

            // 加载FXML并获取控制器实例
            FXMLLoader loader = new FXMLLoader(getClass().getResource("login.fxml"));
            Parent root = loader.load();
            LoginController loginController = loader.getController();
            loginController.setUserController(userController);

            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        }
    } catch(SQLException e){
        System.out.println("Exception:" + e.toString());
    }
}

方案2:复用当前Application实例作为控制器

如果你希望继续用UserInterface作为FXML控制器,可以修改FXML加载逻辑,强制使用当前的UserInterface实例,而不是让FXMLLoader新建:

@Override
public void start(Stage stage) throws Exception {
    String connectionURL = "jdbc:derby://localhost:1527/gymManager";
    String userName = "root";
    String userPassword= "root";
    try {
        conn = DriverManager.getConnection(connectionURL, userName, userPassword);
        if(conn != null){
            System.out.println("Connected to the database");
            ArrayList<User> list = userRepo.read(conn);
            userController.setUserList(list);

            // 创建FXMLLoader实例并指定控制器为当前对象
            FXMLLoader loader = new FXMLLoader(getClass().getResource("login.fxml"));
            loader.setController(this); // 关键:复用当前UserInterface实例
            Parent root = loader.load();

            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        }
    } catch(SQLException e){
        System.out.println("Exception:" + e.toString());
    }
}

注意:使用这种方式时,需要移除login.fxml中的fx:controller属性,否则FXMLLoader会抛出异常(因为不能同时指定控制器和使用fxml中的配置)。

额外优化建议
  • 给setUserList()方法的参数加上泛型约束,避免强制类型转换:
public void setUserList(ArrayList<User> list){
    userList = list;
    for (User user : userList) {
        String firstName = user.getFirstName();
        System.out.println("Users in the UserController: " + firstName);
    }
}
  • 尽量避免使用静态变量存储业务数据,改用依赖注入的方式传递对象,保证代码的可维护性和可测试性。

内容的提问来源于stack exchange,提问作者Tom Budge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:37:07