gpt4 book ai didi

java - 单例中的字段意外为空 - 为什么?

转载 作者:行者123 更新时间:2023-12-02 02:31:51 25 4
gpt4 key购买 nike

我在 JavaFX 程序中有以下单例,其目的是使在应用程序的不同屏幕之间切换变得更容易:

public class ScreenManager() {

private Stage mainStage;

private static ScreenManager instance;

private ScreenManager() {
// TODO
}

public static ScreenManager getInstance() {
if (instance == null ) {
return new ScreenManager();
} else {
return instance;
}
}

public void initialize(Stage mainStage) {
this.mainStage = mainStage;
}

public void switchToScreen(String fxmlPath) {
Parent newScreenRoot;

try {
URL pathToFxml = getClass().getResource(fxmlPath);
newScreenRoot = fxmlLoader.load(pathToFxml);
} catch (IOException e) {
throw new IllegalArgumentException("Failed to load FXML", e);
}

Scene newScreen = new Scene(newScreenRoot);
mainStage.setScene(newScreen);
mainStage.setMaximized(true);
}

}

在 JavaFX 的 start() 方法期间,通过对主阶段的引用来调用 Initialize。

但是,当我稍后调用 getInstance() 并尝试切换屏幕时,我失败并出现 NullPointerException,因为 mainStage 为 null。似乎该字段在第一次使用和后续使用之间变得为空。怎么办?

为什么会发生这种情况?

最佳答案

你从不初始化instance,所以你的getInstance()方法每次都会返回一个新对象(这几乎与单例相反;你让它变得非常困难多次使用同一个实例...)。

你需要

public static ScreenManager getInstance() {
if (instance == null ) {
instance = new ScreenManager();
}
return instance;
}

几点评论:许多程序员不鼓励使用单例模式,因为它有很多问题。您可能会考虑使用依赖注入(inject)。另外,由于此单例的主要目的似乎是提供对阶段的访问,请注意,您可以通过 Node.getScene().getWindow() 获取对包含在任何节点中的阶段的引用。 > (如果您需要特定于 Stage 的功能,您可能需要向下转换结果)。由于 Controller 始终可以访问 UI 层次结构中的某些节点,因此您可能根本不需要它。

最后,如果您确实决定需要/想要使用单例,实现单例模式的另一种方法是使用仅具有一个值的枚举:

import java.io.IOException;
import java.net.URL;

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public enum ScreenManager {

INSTANCE ;

private Stage mainStage;


public void initialize(Stage mainStage) {
this.mainStage = mainStage;
}

public void switchToScreen(String fxmlPath) {
Parent newScreenRoot;

try {
URL pathToFxml = getClass().getResource(fxmlPath);
newScreenRoot = FXMLLoader.load(pathToFxml);
} catch (IOException e) {
throw new IllegalArgumentException("Failed to load FXML", e);
}

Scene newScreen = new Scene(newScreenRoot);
mainStage.setScene(newScreen);
mainStage.setMaximized(true);
}

}

然后你可以做类似的事情

ScreenManager.INSTANCE.initialize(primaryStage);
ScreenManager.INSTANCE.switchToScreen(...);

等等

一般来说,这种方法比直接实现它有一些优点:首先,这是立即线程安全的,而我在本文顶部发布的解决方案则不然。

关于java - 单例中的字段意外为空 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46965580/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com