为什么我的单身人士 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
可以解决问题。
您应该重新组织代码以防止初始化循环。 UserManager
和 Engine
在初始化期间不应相互依赖。
请注意,按照另一个答案中的建议执行 private static Engine instance = new Engine()
不会修复您的初始化循环。
我一直在写程序。程序中的一切都由 '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
可以解决问题。
您应该重新组织代码以防止初始化循环。 UserManager
和 Engine
在初始化期间不应相互依赖。
请注意,按照另一个答案中的建议执行 private static Engine instance = new Engine()
不会修复您的初始化循环。