同一对象的不同对象引用?

5

我最近询问了关于从另一个类获取类的唯一实例的问题。

(在Java中如何从另一个类获取特定类的实例?)

所以,我正在尝试让它起作用:

我的Application

public class Application
{

    // I will always have only one instance of Application

    private static Application _application;

    // Every instance of Application (one in my case) should have its own View

    private View view;

    // Constructor for new instance of Application

    private Application()
    {
        view = new View();
    }

    // Getter for my unique instance of Application

    public static Application getSharedApplication()
    {
        if (_application == null)
            _application = new Application();
        return _application;
    }

    // Main class

    public static void main(String[] args)
    {
        // So I'm accessing my instance of Application
        Application application1 = getSharedApplication();

        // Here is object reference
        System.out.println(application1);

        // And now I'm accessing the same instance of Application through instance of View
        Application application2 = application1.view.getApplication();

        // Here is object reference
        System.out.println(application2);
    }

}

我的 视图

public class View
{

    // I'm accessing my instance of Application again

    public static Application application = Application.getSharedApplication();

    // This method should return my unique instance of Application

    public Application getApplication()
    {
        return application;
    }

}

问题在于main方法返回的是不同的对象引用。
Application@1430b5c
Application@c2a132

我的代码有什么问题?


它使用单例和其他形式的全局状态,这就是它的问题所在。 - tereško
当你需要单例时,为什么不使用枚举? - Ajay George
4个回答

7

以下是发生的情况:

  • 程序首先调用Application application1 = getSharedApplication();
  • 然后调用静态方法,该方法调用new Application() - 该调用需要加载视图类(View class),该类是Application的成员。
  • 视图类被加载,其静态成员被初始化并运行getSharedApplication();(此时注意,_application仍为空)。这也创建了一个新的Application()

现在你有两个应用程序实例。

请注意,如果将View v = new View();添加为您的主要代码的第一行,则只有一个Application实例(它从View的静态变量中加载一次)。当您深入思考时,这是有意义的,但不太直观...


很好。这个例子应该放在“为什么单例几乎总是不好的想法”页面上! - Jochen
全局状态(静态变量)很难理解,特别是当存在循环引用时! - assylias
1
单例模式并不是一个坏主意,但是它们可能被实现得很糟糕,就像这里一样。 - Louis Wasserman

4
一般来说,解决这种问题的方法是:使用调试器!例如,您可以在 Application 的构造函数中设置断点,运行程序,并在构造函数第二次执行时检查堆栈。
如果您这样做,您会注意到类似于以下内容:
Application.<init>() line: 21   
Application.getSharedApplication() line: 31 
View.<clinit>() line: 59    
Application.<init>() line: 23   
Application.getSharedApplication() line: 31 

也就是说,该视图希望在共享应用程序完全构建之前(并且在后者存储在静态字段之前)获取共享应用程序。

1
如果您像下面这样更改View的初始化
public static Application getSharedApplication() {

    if(_application == null)
    {
        _application = new Application();
        view = new View();
    }

你会发现只有一个实例被创建了。 原因是在应用程序完全初始化之前,你创建了View实例。因为静态变量在第一次请求类时加载,所以会出现这种行为。

无论如何,我学到了永远不要这样做 :) 谢谢 :)


0

getSharedApplication() 方法应该使用 synchronized 关键字。否则,两个线程可能会进入第一个 if 语句块并创建不同的变量。

我不确定这是否是此处发生的情况。尝试在各处添加调试/打印语句,以便您可以跟踪实际发生的情况。


@assylias 我知道,但是如果这个方法没有同步,他以后会遇到麻烦的。 - Sarel Botha
你说得很有道理 - 我只是想说这不是问题的原因。 - assylias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接