为什么我的单例类会抛出StackOverflower错误?

时间:2016-04-01 00:30:48

标签: java singleton stack-overflow

我一直在写一个程序。程序中的所有内容都由“引擎”类控制。因此我把它变成了单身人士。这是我当前运行得很好的代码。

    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;

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

这是stacktrace:

Exception in thread "main" java.lang.StackOverflowError
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

提前致谢!

1 个答案:

答案 0 :(得分:4)

堆栈跟踪显示以下循环:

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()来电尚未返回。

这就是在调用Engine.instance之前在构造函数中分配new UserManager()来解决问题的原因。

您应该重新组织代码以防止初始化循环。 <{1}}和UserManager在初始化期间不应相互依赖。

请注意,按照另一个答案中的建议执行Engine将无法修复初始化循环。