为什么我的单身人士 class 会抛出 StackOverflowerror?

Why does my singleton class throw a StackOverflowerror?

我一直在写程序。程序中的一切都由 'Engine' class 控制。因此我把它变成了单身人士。这是我当前运行良好的代码。

    package org.bautista.cybersafe.core;

import javax.swing.SwingUtilities;

import org.bautista.cybersafe.ui.MainUI;
import org.bautista.cybersafe.util.Cache;
import org.bautista.cybersafe.util.Config;
import org.bautista.cybersafe.util.account.Account;
import org.bautista.cybersafe.util.account.AccountManager;
import org.bautista.cybersafe.util.user.User;
import org.bautista.cybersafe.util.user.UserManager;

public class Engine {
    private static Engine instance;
    private AccountManager accountManager;
    private final MainUI ui;
    private final UserManager userManager;
    private final Config config;
    private User currentUser;

    private Engine() {
        instance = this; //THIS IS LINE 22
        if (!Cache.cacheExists()) {
            if (!Cache.createCache()) {
                System.out.println("Error creating cache.");
            }
        }
        config = new Config();
        userManager = new UserManager();
        ui = new MainUI();
    }

    public static Engine getInstance() {
        return instance == null ? instance = new Engine() : instance;
    }

    public void setCurrentUser(User user) {
        currentUser = user;
    }

    public User getCurrentUser() {
        return currentUser;
    }

    public AccountManager getAccountManager() {
        return accountManager;
    }

    public Config getConfig() {
        return config;
    }

    public UserManager getUserManager() {
        return userManager;
    }

    public void logOut() {
        currentUser = null;
        accountManager = null;
        ui.showLogin();
    }

    public void openAccountViewer(final Account account) {
        ui.showAccount(account);
        ui.setTitle("Cyber Safe - [" + currentUser.getUsername() + "] -"
                + account.getName());
    }

    public void openCreateAccountScreen() {
        ui.showCreateAccount();
    }

    public void openCreateUserScreen() {
        ui.showCreateUser();
    }

    public void openLoginScreen() {
        ui.showLogin();
        ui.setTitle("Cyber Safe");
    }

    public void openSafeScreen() {
        if (accountManager == null) {
            accountManager = new AccountManager(currentUser);
        }
        ui.showSafe();
        ui.setTitle("Cyber Safe - [" + currentUser.getUsername() + "]");
    }

    public void refreshUI() {
        ui.refresh();
    }

    public void updateAccountPreviews() {
        ui.updateAccountScroller();
    }

    public void run() {
        try {
            SwingUtilities.invokeAndWait(() -> ui.setVisible(true));
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

}

当我注释掉第22行时

instance = this;

我收到 Whosebugerror。当我调试程序时,我发现引擎构造函数被重复调用,就好像它在执行递归,直到我最终得到错误。为什么会这样?我的#getInstance() 方法不应该将实例作为 'Engine' class 的新实例启动吗?

这是堆栈跟踪:

Exception in thread "main" java.lang.WhosebugError
at java.io.InputStream.<init>(InputStream.java:45)
at java.io.FileInputStream.<init>(FileInputStream.java:123)
at org.bautista.cybersafe.util.Config.loadProperties(Config.java:67)
at org.bautista.cybersafe.util.Config.<init>(Config.java:29)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:28)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)

And here is the full project on Github

提前致谢!

堆栈跟踪显示以下循环:

at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)

Engine.getInstance() 呼叫 new Engine().
new Engine() 呼叫 new UserManager().
new UserManager() 呼叫 UserManager.loadUsers().
UserManager.loadUsers() 调用了 Engine.getInstance(),但尚未分配 Engine.instance,因为之前的 new Engine() 调用尚未返回。

这就是为什么在调用 new UserManager() 之前在构造函数中分配 Engine.instance 可以解决问题。

您应该重新组织代码以防止初始化循环。 UserManagerEngine 在初始化期间不应相互依赖。

请注意,按照另一个答案中的建议执行 private static Engine instance = new Engine() 不会修复您的初始化循环。