Different object references for the same(?) object
Asked Answered
C

4

5

I have asked about getting unique instance of class from another class recently.

( How to get specific instance of class from another class in Java? )

So, I am trying to make it work:

My 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);
    }

}

My View:

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;
    }

}

The problem is that main method returns different object references.

Application@1430b5c
Application@c2a132

What's wrong with my code?

Crossindex answered 16/8, 2012 at 17:52 Comment(2)
It uses a singletons and other forms of global state , that's what is wrong with it.Doig
Why not use enums when you need Singletons.?Bork
S
7

Here is what happens:

  • the program first calls Application application1 = getSharedApplication();
  • that in turn calls the static method which calls new Application() - that call needs to load the View class, which is a member of Application.
  • the View class is loaded and its static member is initialised and runs getSharedApplication(); (note that at this stage, _application is still null). That creates a new Application() too

You now have 2 Application instances.

Note that if you add View v = new View(); as the first line of your main, you only have one instance of Application (which gets loaded once from the static variable of View). That makes sense when you think hard about it but is not very intuitive...

Spherule answered 16/8, 2012 at 18:5 Comment(3)
Beautiful. This example should go on the page for "Why Singleton is almost always a bad idea"!Nucleate
Global state (static variables) is hard to reason about, especially when there are cyclical references!Spherule
Singletons aren't a bad idea, but they can be implemented poorly, as they are here.Williamsen
S
4

The general answer to such questions is: Use a debugger! For instance, you might set a break point in the constructor of Application, run your program, and inspect the stack when the constructor executes for the second time.

If you do this, you'll note something like this:

Application.<init>() line: 21   
Application.getSharedApplication() line: 31 
View.<clinit>() line: 59    
Application.<init>() line: 23   
Application.getSharedApplication() line: 31 

That is, the view wants to get the shared application before the shared application has been fully constructed (and before the latter is stored in the static field).

Sforza answered 16/8, 2012 at 18:3 Comment(0)
S
1

If you change initialization of View like below

public static Application getSharedApplication() {

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

You will find only one instance is getting created. Reason is you are creating View instance before Application is completely initialized. Because static variables are loaded when class is requested for the first time so this behavior is happening.

Anyway I learnt that never do this :) thanks:)

Sella answered 16/8, 2012 at 18:31 Comment(0)
E
0

The getSharedApplication() method should use the synchronized keyword. Otherwise two threads may enter the first if statement block and both create different variables.

I'm not sure if that is what is happening here. Try adding debug/print statements everywhere so you can follow what is really happening.

Equestrian answered 16/8, 2012 at 18:6 Comment(2)
@Spherule I know, but he's asking for trouble later on if the method isn't synchronized.Equestrian
You make a fair point - I'm just saying that it is not the cause of the issue.Spherule

© 2022 - 2024 — McMap. All rights reserved.